Updates to 3rd party libraries

Add Dockerfile and specific docker-php.ini
This commit is contained in:
Ryan Prather 2018-08-28 21:27:13 -04:00
parent 9edd6c1c35
commit d52454d1bb
511 changed files with 45950 additions and 2729 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/.buildpath
/.project
/.settings/

View File

@ -1,3 +1,5 @@
## v1.3.3
## v1.3.2
- Initial GitHub load
- Previous versions loaded on [SourceForge](https://sourceforge.net/projects/sagacity/)

6
Dockerfile Normal file
View File

@ -0,0 +1,6 @@
FROM php:7.2.8-apache-stretch
COPY conf/docker-php.ini /usr/local/etc/php/php.ini
RUN apt update && apt -y install zlib1g-dev mysql-client
RUN docker-php-ext-install mysqli zip
RUN mkdir /var/log/sagacity && chown www-data:www-data /var/log/sagacity
EXPOSE 80

14
conf/docker-php.ini Normal file
View File

@ -0,0 +1,14 @@
memory_limit=1024M
error_reporting=E_ALL
display_errors=On
display_startup_errors=On
html_errors=On
variables_order="GPCS"
request_order="GPCS"
post_max_size=1G
include_path="./:/var/www/html:/var/www/html/classes:/var/www/html/inc"
file_uploads=On
upload_max_filesize=1G
allow_url_fopen=On
allow_url_include=Off
date.timezone=America/Indiana/Indianapolis

View File

@ -15,6 +15,7 @@
* - Nov 14, 2017 - File created
* - May 24, 2018 - Updated constants for 1.3.2 release
* - Jun 2, 2018 - Added new STIG_EXCLUSIONS constant to permanently exclude STIGs
* - Aug 28, 2018 - Updated constants for 1.3.3 release
*/
// @new
/**
@ -29,8 +30,8 @@ define('E_DEBUG', 65535);
define('DOC_ROOT', '{DOC_ROOT}');
define('PWD_FILE', '{PWD_FILE}');
define('TMP', '{TMP_PATH}');
define('VER', '1.3.2');
define('REL_DATE', '2018-05-31');
define('VER', '1.3.3');
define('REL_DATE', '2018-08-31');
define('LOG_LEVEL', '{E_ERROR}');
define('LOG_PATH', '{LOG_PATH}');
define('SALT', '{SALT}');

1
inc/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/passwd

View File

@ -1,12 +1,31 @@
{
"require" : {
"phpoffice/phpspreadsheet" : "^1.0",
"cocur/background-process" : "^0.7.0",
"tecnickcom/tcpdf" : "^6.2",
"pacificsec/cpe" : "^1.0",
"monolog/monolog": "^1.23"
},
"require-dev" : {
"phpunit/phpunit" : "^6.2"
}
}
"require" : {
"phpoffice/phpspreadsheet" : "~1.4",
"cocur/background-process" : "~0.7",
"tecnickcom/tcpdf" : "~6.2",
"pacificsec/cpe" : "1.0.1",
"godsgood33/php-db" : "~1.3"
},
"require-dev" : {
"phpunit/phpunit" : "~7.3"
},
"type" : "project",
"homepage" : "https://cyberperspectives.com",
"license" : "Apache-2.0",
"authors" : [{
"name" : "Ryan Prather",
"email" : "ryan.prather@cyberperspectives.com",
"role" : "Braun"
}, {
"name" : "Jeff Odegard",
"email" : "jeff.odegard@cyberperspectives.com",
"role" : "Brains"
}
],
"keywords" : [
"security",
"disa",
"rmf"
],
"name" : "cyberperspectives\\sagacity"
}

452
inc/composer.lock generated
View File

@ -1,10 +1,10 @@
{
"_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",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "92ac4709f5221f74a1c7f00e59df8ad7",
"content-hash": "184b710525eca347d52d3a2062cdf1c7",
"packages": [
{
"name": "cocur/background-process",
@ -44,6 +44,148 @@
],
"time": "2017-02-11T12:41:41+00:00"
},
{
"name": "godsgood33/php-db",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/godsgood33/php-db.git",
"reference": "cdf01f123c16dcb0b294b3b9013557e2d472f1c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/godsgood33/php-db/zipball/cdf01f123c16dcb0b294b3b9013557e2d472f1c9",
"reference": "cdf01f123c16dcb0b294b3b9013557e2d472f1c9",
"shasum": ""
},
"require": {
"monolog/monolog": "~1.23"
},
"require-dev": {
"phpunit/phpunit": "~7.2"
},
"type": "library",
"autoload": {
"psr-4": {
"Godsgood33\\Php_Db\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Ryan Prather",
"email": "godsgood33@gmail.com",
"role": "Developer"
}
],
"description": "PHP Database Library",
"homepage": "https://github.com/godsgood33/php-db",
"keywords": [
"database",
"library",
"mysql",
"mysqli"
],
"time": "2018-06-07T18:30:13+00:00"
},
{
"name": "markbaker/complex",
"version": "1.4.6",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "a78d82ae4e682c3809fc3023d1b0ce654f6ab12b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/a78d82ae4e682c3809fc3023d1b0ce654f6ab12b",
"reference": "a78d82ae4e682c3809fc3023d1b0ce654f6ab12b",
"shasum": ""
},
"require": {
"php": "^5.6.0|^7.0.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
"phpcompatibility/php-compatibility": "^8.0",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "2.*",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^4.8.35|^5.4.0",
"sebastian/phpcpd": "2.*",
"squizlabs/php_codesniffer": "^3.3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
},
"files": [
"classes/src/functions/abs.php",
"classes/src/functions/acos.php",
"classes/src/functions/acosh.php",
"classes/src/functions/acot.php",
"classes/src/functions/acoth.php",
"classes/src/functions/acsc.php",
"classes/src/functions/acsch.php",
"classes/src/functions/argument.php",
"classes/src/functions/asec.php",
"classes/src/functions/asech.php",
"classes/src/functions/asin.php",
"classes/src/functions/asinh.php",
"classes/src/functions/atan.php",
"classes/src/functions/atanh.php",
"classes/src/functions/conjugate.php",
"classes/src/functions/cos.php",
"classes/src/functions/cosh.php",
"classes/src/functions/cot.php",
"classes/src/functions/coth.php",
"classes/src/functions/csc.php",
"classes/src/functions/csch.php",
"classes/src/functions/exp.php",
"classes/src/functions/inverse.php",
"classes/src/functions/ln.php",
"classes/src/functions/log2.php",
"classes/src/functions/log10.php",
"classes/src/functions/negative.php",
"classes/src/functions/pow.php",
"classes/src/functions/rho.php",
"classes/src/functions/sec.php",
"classes/src/functions/sech.php",
"classes/src/functions/sin.php",
"classes/src/functions/sinh.php",
"classes/src/functions/sqrt.php",
"classes/src/functions/tan.php",
"classes/src/functions/tanh.php",
"classes/src/functions/theta.php",
"classes/src/operations/add.php",
"classes/src/operations/subtract.php",
"classes/src/operations/multiply.php",
"classes/src/operations/divideby.php",
"classes/src/operations/divideinto.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
],
"time": "2018-07-31T08:38:40+00:00"
},
{
"name": "monolog/monolog",
"version": "1.23.0",
@ -124,33 +266,59 @@
},
{
"name": "pacificsec/cpe",
"version": "1.0.0",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/pacificsec/cpe.git",
"reference": "3d78d66fc4ea249b6f353a7c48f426835a792d11"
"reference": "52cc49e04388ba00493be634287f6ce3efb30afc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pacificsec/cpe/zipball/3d78d66fc4ea249b6f353a7c48f426835a792d11",
"reference": "3d78d66fc4ea249b6f353a7c48f426835a792d11",
"url": "https://api.github.com/repos/pacificsec/cpe/zipball/52cc49e04388ba00493be634287f6ce3efb30afc",
"reference": "52cc49e04388ba00493be634287f6ce3efb30afc",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"notification-url": "https://packagist.org/downloads/"
"autoload": {
"psr-4": {
"PacificSec\\CPE\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Franco",
"email": "antonio.franco@pacificsec.com"
}
],
"description": "CPE: Common Platform Enumeration for PHP",
"homepage": "https://github.com/pacificsec/cpe",
"keywords": [
"cpe",
"cve",
"pacificsec",
"security"
],
"time": "2018-08-22T17:55:09+00:00"
},
{
"name": "phpoffice/phpspreadsheet",
"version": "1.2.1",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "36acc372875c4d894dc093825ce4f62209db5a76"
"reference": "125f462a718956f37d81305ca0df4f17cef0f3b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/36acc372875c4d894dc093825ce4f62209db5a76",
"reference": "36acc372875c4d894dc093825ce4f62209db5a76",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/125f462a718956f37d81305ca0df4f17cef0f3b9",
"reference": "125f462a718956f37d81305ca0df4f17cef0f3b9",
"shasum": ""
},
"require": {
@ -166,6 +334,7 @@
"ext-xmlwriter": "*",
"ext-zip": "*",
"ext-zlib": "*",
"markbaker/complex": "^1.4.1",
"php": "^5.6|^7.0",
"psr/simple-cache": "^1.0"
},
@ -175,7 +344,7 @@
"jpgraph/jpgraph": "^4.0",
"mpdf/mpdf": "^7.0.0",
"phpunit/phpunit": "^5.7",
"squizlabs/php_codesniffer": "^2.7",
"squizlabs/php_codesniffer": "^3.3",
"tecnickcom/tcpdf": "^6.2"
},
"suggest": {
@ -223,7 +392,7 @@
"xls",
"xlsx"
],
"time": "2018-04-10T03:53:16+00:00"
"time": "2018-08-06T02:58:06+00:00"
},
{
"name": "psr/log",
@ -440,16 +609,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.8.0",
"version": "1.8.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "478465659fd987669df0bd8a9bf22a8710e5f1b6"
"reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/478465659fd987669df0bd8a9bf22a8710e5f1b6",
"reference": "478465659fd987669df0bd8a9bf22a8710e5f1b6",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
"reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
"shasum": ""
},
"require": {
@ -484,26 +653,26 @@
"object",
"object graph"
],
"time": "2018-05-29T17:25:09+00:00"
"time": "2018-06-11T23:09:50+00:00"
},
{
"name": "phar-io/manifest",
"version": "1.0.1",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/phar-io/manifest.git",
"reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
"reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0",
"reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
"url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
"reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-phar": "*",
"phar-io/version": "^1.0.1",
"phar-io/version": "^2.0",
"php": "^5.6 || ^7.0"
},
"type": "library",
@ -539,20 +708,20 @@
}
],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"time": "2017-03-05T18:14:27+00:00"
"time": "2018-07-08T19:23:20+00:00"
},
{
"name": "phar-io/version",
"version": "1.0.1",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/phar-io/version.git",
"reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
"reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df",
"reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
"url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
"reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
"shasum": ""
},
"require": {
@ -586,7 +755,7 @@
}
],
"description": "Library for handling version information and constraints",
"time": "2017-03-05T17:38:23+00:00"
"time": "2018-07-08T19:19:57+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@ -742,16 +911,16 @@
},
{
"name": "phpspec/prophecy",
"version": "1.7.6",
"version": "1.8.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
"reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
"reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
"shasum": ""
},
"require": {
@ -763,12 +932,12 @@
},
"require-dev": {
"phpspec/phpspec": "^2.5|^3.2",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7.x-dev"
"dev-master": "1.8.x-dev"
}
},
"autoload": {
@ -801,44 +970,44 @@
"spy",
"stub"
],
"time": "2018-04-18T13:57:24+00:00"
"time": "2018-08-05T17:53:17+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "5.3.2",
"version": "6.0.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "c89677919c5dd6d3b3852f230a663118762218ac"
"reference": "865662550c384bc1db7e51d29aeda1c2c161d69a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac",
"reference": "c89677919c5dd6d3b3852f230a663118762218ac",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a",
"reference": "865662550c384bc1db7e51d29aeda1c2c161d69a",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlwriter": "*",
"php": "^7.0",
"phpunit/php-file-iterator": "^1.4.2",
"php": "^7.1",
"phpunit/php-file-iterator": "^2.0",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^2.0.1",
"phpunit/php-token-stream": "^3.0",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.0",
"sebastian/environment": "^3.1",
"sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1"
},
"require-dev": {
"phpunit/phpunit": "^6.0"
"phpunit/phpunit": "^7.0"
},
"suggest": {
"ext-xdebug": "^2.5.5"
"ext-xdebug": "^2.6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.3.x-dev"
"dev-master": "6.0-dev"
}
},
"autoload": {
@ -864,29 +1033,29 @@
"testing",
"xunit"
],
"time": "2018-04-06T15:36:58+00:00"
"time": "2018-06-01T07:51:50+00:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "1.4.5",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
"reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cecbc684605bb0cc288828eb5d65d93d5c676d3c",
"reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
"php": "^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
"dev-master": "2.0.x-dev"
}
},
"autoload": {
@ -901,7 +1070,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
@ -911,7 +1080,7 @@
"filesystem",
"iterator"
],
"time": "2017-11-27T13:52:08+00:00"
"time": "2018-06-11T11:44:00+00:00"
},
{
"name": "phpunit/php-text-template",
@ -956,28 +1125,28 @@
},
{
"name": "phpunit/php-timer",
"version": "1.0.9",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
"reference": "8b8454ea6958c3dee38453d3bd571e023108c91f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
"reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f",
"reference": "8b8454ea6958c3dee38453d3bd571e023108c91f",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
"dev-master": "2.0-dev"
}
},
"autoload": {
@ -992,7 +1161,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
@ -1001,33 +1170,33 @@
"keywords": [
"timer"
],
"time": "2017-02-26T11:10:40+00:00"
"time": "2018-02-01T13:07:23+00:00"
},
{
"name": "phpunit/php-token-stream",
"version": "2.0.2",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "791198a2c6254db10131eecfe8c06670700904db"
"reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
"reference": "791198a2c6254db10131eecfe8c06670700904db",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace",
"reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": "^7.0"
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^6.2.4"
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
"dev-master": "3.0-dev"
}
},
"autoload": {
@ -1050,40 +1219,40 @@
"keywords": [
"tokenizer"
],
"time": "2017-11-27T05:48:46+00:00"
"time": "2018-02-01T13:16:43+00:00"
},
{
"name": "phpunit/phpunit",
"version": "6.5.8",
"version": "7.3.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b"
"reference": "34705f81bddc3f505b9599a2ef96e2b4315ba9b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b",
"reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/34705f81bddc3f505b9599a2ef96e2b4315ba9b8",
"reference": "34705f81bddc3f505b9599a2ef96e2b4315ba9b8",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.1",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"myclabs/deep-copy": "^1.6.1",
"phar-io/manifest": "^1.0.1",
"phar-io/version": "^1.0",
"php": "^7.0",
"myclabs/deep-copy": "^1.7",
"phar-io/manifest": "^1.0.2",
"phar-io/version": "^2.0",
"php": "^7.1",
"phpspec/prophecy": "^1.7",
"phpunit/php-code-coverage": "^5.3",
"phpunit/php-file-iterator": "^1.4.3",
"phpunit/php-code-coverage": "^6.0.7",
"phpunit/php-file-iterator": "^2.0.1",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^1.0.9",
"phpunit/phpunit-mock-objects": "^5.0.5",
"sebastian/comparator": "^2.1",
"sebastian/diff": "^2.0",
"phpunit/php-timer": "^2.0",
"sebastian/comparator": "^3.0",
"sebastian/diff": "^3.0",
"sebastian/environment": "^3.1",
"sebastian/exporter": "^3.1",
"sebastian/global-state": "^2.0",
@ -1092,15 +1261,15 @@
"sebastian/version": "^2.0.1"
},
"conflict": {
"phpdocumentor/reflection-docblock": "3.0.2",
"phpunit/dbunit": "<3.0"
"phpunit/phpunit-mock-objects": "*"
},
"require-dev": {
"ext-pdo": "*"
},
"suggest": {
"ext-soap": "*",
"ext-xdebug": "*",
"phpunit/php-invoker": "^1.1"
"phpunit/php-invoker": "^2.0"
},
"bin": [
"phpunit"
@ -1108,7 +1277,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.5.x-dev"
"dev-master": "7.3-dev"
}
},
"autoload": {
@ -1134,66 +1303,7 @@
"testing",
"xunit"
],
"time": "2018-04-10T11:38:34+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "5.0.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "3eaf040f20154d27d6da59ca2c6e28ac8fd56dce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3eaf040f20154d27d6da59ca2c6e28ac8fd56dce",
"reference": "3eaf040f20154d27d6da59ca2c6e28ac8fd56dce",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.5",
"php": "^7.0",
"phpunit/php-text-template": "^1.2.1",
"sebastian/exporter": "^3.1"
},
"conflict": {
"phpunit/phpunit": "<6.0"
},
"require-dev": {
"phpunit/phpunit": "^6.5"
},
"suggest": {
"ext-soap": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Mock Object library for PHPUnit",
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
"keywords": [
"mock",
"xunit"
],
"time": "2018-05-29T13:50:43+00:00"
"time": "2018-08-22T06:39:21+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@ -1242,30 +1352,30 @@
},
{
"name": "sebastian/comparator",
"version": "2.1.3",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "34369daee48eafb2651bea869b4b15d75ccc35f9"
"reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9",
"reference": "34369daee48eafb2651bea869b4b15d75ccc35f9",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
"reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
"shasum": ""
},
"require": {
"php": "^7.0",
"sebastian/diff": "^2.0 || ^3.0",
"php": "^7.1",
"sebastian/diff": "^3.0",
"sebastian/exporter": "^3.1"
},
"require-dev": {
"phpunit/phpunit": "^6.4"
"phpunit/phpunit": "^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1.x-dev"
"dev-master": "3.0-dev"
}
},
"autoload": {
@ -1302,32 +1412,33 @@
"compare",
"equality"
],
"time": "2018-02-01T13:46:46+00:00"
"time": "2018-07-12T15:12:46+00:00"
},
{
"name": "sebastian/diff",
"version": "2.0.1",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd"
"reference": "366541b989927187c4ca70490a35615d3fef2dce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
"reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce",
"reference": "366541b989927187c4ca70490a35615d3fef2dce",
"shasum": ""
},
"require": {
"php": "^7.0"
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^6.2"
"phpunit/phpunit": "^7.0",
"symfony/process": "^2 || ^3.3 || ^4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
"dev-master": "3.0-dev"
}
},
"autoload": {
@ -1352,9 +1463,12 @@
"description": "Diff implementation",
"homepage": "https://github.com/sebastianbergmann/diff",
"keywords": [
"diff"
"diff",
"udiff",
"unidiff",
"unified diff"
],
"time": "2017-08-03T08:09:46+00:00"
"time": "2018-06-10T07:54:39+00:00"
},
{
"name": "sebastian/environment",

View File

@ -186,7 +186,7 @@ class BackgroundProcess {
/**
* @param int $pid PID of process to resume
*
* @return Cocur\BackgroundProcess\BackgroundProcess
* @return BackgroundProcess
*/
static public function createFromPID($pid) {
$process = new self();

View File

@ -6,5 +6,46 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
'abede361264e2ae69ec1eee813a101af' => $vendorDir . '/markbaker/complex/classes/src/functions/abs.php',
'21a5860fbef5be28db5ddfbc3cca67c4' => $vendorDir . '/markbaker/complex/classes/src/functions/acos.php',
'1546e3f9d127f2a9bb2d1b6c31c26ef1' => $vendorDir . '/markbaker/complex/classes/src/functions/acosh.php',
'd2516f7f4fba5ea5905f494b4a8262e0' => $vendorDir . '/markbaker/complex/classes/src/functions/acot.php',
'4511163d560956219b96882c0980b65e' => $vendorDir . '/markbaker/complex/classes/src/functions/acoth.php',
'c361f5616dc2a8da4fa3e137077cd4ea' => $vendorDir . '/markbaker/complex/classes/src/functions/acsc.php',
'02d68920fc98da71991ce569c91df0f6' => $vendorDir . '/markbaker/complex/classes/src/functions/acsch.php',
'88e19525eae308b4a6aa3419364875d3' => $vendorDir . '/markbaker/complex/classes/src/functions/argument.php',
'60e8e2d0827b58bfc904f13957e51849' => $vendorDir . '/markbaker/complex/classes/src/functions/asec.php',
'13d2f040713999eab66c359b4d79871d' => $vendorDir . '/markbaker/complex/classes/src/functions/asech.php',
'838ab38beb32c68a79d3cd2c007d5a04' => $vendorDir . '/markbaker/complex/classes/src/functions/asin.php',
'bb28eccd0f8f008333a1b3c163d604ac' => $vendorDir . '/markbaker/complex/classes/src/functions/asinh.php',
'9e483de83558c98f7d3feaa402c78cb3' => $vendorDir . '/markbaker/complex/classes/src/functions/atan.php',
'36b74b5b765ded91ee58c8ee3c0e85e3' => $vendorDir . '/markbaker/complex/classes/src/functions/atanh.php',
'05c15ee9510da7fd6bf6136f436500c0' => $vendorDir . '/markbaker/complex/classes/src/functions/conjugate.php',
'd3208dfbce2505e370788f9f22f6785f' => $vendorDir . '/markbaker/complex/classes/src/functions/cos.php',
'141cf1fb3a3046f8b64534b0ebab33ca' => $vendorDir . '/markbaker/complex/classes/src/functions/cosh.php',
'be660df75fd0dbe7fa7c03b7434b3294' => $vendorDir . '/markbaker/complex/classes/src/functions/cot.php',
'01e31ea298a51bc9e91517e3ce6b9e76' => $vendorDir . '/markbaker/complex/classes/src/functions/coth.php',
'803ddd97f7b1da68982a7b087c3476f6' => $vendorDir . '/markbaker/complex/classes/src/functions/csc.php',
'3001cdfd101ec3c32da34ee43c2e149b' => $vendorDir . '/markbaker/complex/classes/src/functions/csch.php',
'77b2d7629ef2a93fabb8c56754a91051' => $vendorDir . '/markbaker/complex/classes/src/functions/exp.php',
'4a4471296dec796c21d4f4b6552396a9' => $vendorDir . '/markbaker/complex/classes/src/functions/inverse.php',
'c3e9897e1744b88deb56fcdc39d34d85' => $vendorDir . '/markbaker/complex/classes/src/functions/ln.php',
'a83cacf2de942cff288de15a83afd26d' => $vendorDir . '/markbaker/complex/classes/src/functions/log2.php',
'6a861dacc9ee2f3061241d4c7772fa21' => $vendorDir . '/markbaker/complex/classes/src/functions/log10.php',
'4d2522d968c8ba78d6c13548a1b4200e' => $vendorDir . '/markbaker/complex/classes/src/functions/negative.php',
'fd587ca933fc0447fa5ab4843bdd97f7' => $vendorDir . '/markbaker/complex/classes/src/functions/pow.php',
'383ef01c62028fc78cd4388082fce3c2' => $vendorDir . '/markbaker/complex/classes/src/functions/rho.php',
'150fbd1b95029dc47292da97ecab9375' => $vendorDir . '/markbaker/complex/classes/src/functions/sec.php',
'549abd9bae174286d660bdaa07407c68' => $vendorDir . '/markbaker/complex/classes/src/functions/sech.php',
'6bfbf5eaea6b17a0ed85cb21ba80370c' => $vendorDir . '/markbaker/complex/classes/src/functions/sin.php',
'22efe13f1a497b8e199540ae2d9dc59c' => $vendorDir . '/markbaker/complex/classes/src/functions/sinh.php',
'e90135ab8e787795a509ed7147de207d' => $vendorDir . '/markbaker/complex/classes/src/functions/sqrt.php',
'bb0a7923ffc6a90919cd64ec54ff06bc' => $vendorDir . '/markbaker/complex/classes/src/functions/tan.php',
'2d302f32ce0fd4e433dd91c5bb404a28' => $vendorDir . '/markbaker/complex/classes/src/functions/tanh.php',
'24dd4658a952171a4ee79218c4f9fd06' => $vendorDir . '/markbaker/complex/classes/src/functions/theta.php',
'e49b7876281d6f5bc39536dde96d1f4a' => $vendorDir . '/markbaker/complex/classes/src/operations/add.php',
'47596e02b43cd6da7700134fd08f88cf' => $vendorDir . '/markbaker/complex/classes/src/operations/subtract.php',
'883af48563631547925fa4c3b48ead07' => $vendorDir . '/markbaker/complex/classes/src/operations/multiply.php',
'f190e3308e6ca23234a2875edc985c03' => $vendorDir . '/markbaker/complex/classes/src/operations/divideby.php',
'ac9e33ce6841aa5bf5d16d465a2f03a7' => $vendorDir . '/markbaker/complex/classes/src/operations/divideinto.php',
);

View File

@ -9,6 +9,9 @@ return array(
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'),
'PacificSec\\CPE\\' => array($vendorDir . '/pacificsec/cpe/src'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Godsgood33\\Php_Db\\' => array($vendorDir . '/godsgood33/php-db/src'),
'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
'Cocur\\BackgroundProcess\\' => array($vendorDir . '/cocur/background-process/src'),
);

View File

@ -47,6 +47,24 @@ class ComposerAutoloaderInit69a0c53551ee5f4e61c53efb549e5e72
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit69a0c53551ee5f4e61c53efb549e5e72::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire69a0c53551ee5f4e61c53efb549e5e72($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire69a0c53551ee5f4e61c53efb549e5e72($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View File

@ -6,19 +6,70 @@ namespace Composer\Autoload;
class ComposerStaticInit69a0c53551ee5f4e61c53efb549e5e72
{
public static $files = array (
'abede361264e2ae69ec1eee813a101af' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/abs.php',
'21a5860fbef5be28db5ddfbc3cca67c4' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acos.php',
'1546e3f9d127f2a9bb2d1b6c31c26ef1' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acosh.php',
'd2516f7f4fba5ea5905f494b4a8262e0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acot.php',
'4511163d560956219b96882c0980b65e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acoth.php',
'c361f5616dc2a8da4fa3e137077cd4ea' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsc.php',
'02d68920fc98da71991ce569c91df0f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsch.php',
'88e19525eae308b4a6aa3419364875d3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/argument.php',
'60e8e2d0827b58bfc904f13957e51849' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asec.php',
'13d2f040713999eab66c359b4d79871d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asech.php',
'838ab38beb32c68a79d3cd2c007d5a04' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asin.php',
'bb28eccd0f8f008333a1b3c163d604ac' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asinh.php',
'9e483de83558c98f7d3feaa402c78cb3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atan.php',
'36b74b5b765ded91ee58c8ee3c0e85e3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atanh.php',
'05c15ee9510da7fd6bf6136f436500c0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/conjugate.php',
'd3208dfbce2505e370788f9f22f6785f' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cos.php',
'141cf1fb3a3046f8b64534b0ebab33ca' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cosh.php',
'be660df75fd0dbe7fa7c03b7434b3294' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cot.php',
'01e31ea298a51bc9e91517e3ce6b9e76' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/coth.php',
'803ddd97f7b1da68982a7b087c3476f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csc.php',
'3001cdfd101ec3c32da34ee43c2e149b' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csch.php',
'77b2d7629ef2a93fabb8c56754a91051' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/exp.php',
'4a4471296dec796c21d4f4b6552396a9' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/inverse.php',
'c3e9897e1744b88deb56fcdc39d34d85' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/ln.php',
'a83cacf2de942cff288de15a83afd26d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log2.php',
'6a861dacc9ee2f3061241d4c7772fa21' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log10.php',
'4d2522d968c8ba78d6c13548a1b4200e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/negative.php',
'fd587ca933fc0447fa5ab4843bdd97f7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/pow.php',
'383ef01c62028fc78cd4388082fce3c2' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/rho.php',
'150fbd1b95029dc47292da97ecab9375' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sec.php',
'549abd9bae174286d660bdaa07407c68' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sech.php',
'6bfbf5eaea6b17a0ed85cb21ba80370c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sin.php',
'22efe13f1a497b8e199540ae2d9dc59c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sinh.php',
'e90135ab8e787795a509ed7147de207d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sqrt.php',
'bb0a7923ffc6a90919cd64ec54ff06bc' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tan.php',
'2d302f32ce0fd4e433dd91c5bb404a28' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tanh.php',
'24dd4658a952171a4ee79218c4f9fd06' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/theta.php',
'e49b7876281d6f5bc39536dde96d1f4a' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/add.php',
'47596e02b43cd6da7700134fd08f88cf' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/subtract.php',
'883af48563631547925fa4c3b48ead07' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/multiply.php',
'f190e3308e6ca23234a2875edc985c03' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideby.php',
'ac9e33ce6841aa5bf5d16d465a2f03a7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideinto.php',
);
public static $prefixLengthsPsr4 = array (
'P' =>
array (
'Psr\\SimpleCache\\' => 16,
'Psr\\Log\\' => 8,
'PhpOffice\\PhpSpreadsheet\\' => 25,
'PacificSec\\CPE\\' => 15,
),
'M' =>
array (
'Monolog\\' => 8,
),
'G' =>
array (
'Godsgood33\\Php_Db\\' => 18,
),
'C' =>
array (
'Complex\\' => 8,
'Cocur\\BackgroundProcess\\' => 24,
),
);
@ -36,10 +87,22 @@ class ComposerStaticInit69a0c53551ee5f4e61c53efb549e5e72
array (
0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet',
),
'PacificSec\\CPE\\' =>
array (
0 => __DIR__ . '/..' . '/pacificsec/cpe/src',
),
'Monolog\\' =>
array (
0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog',
),
'Godsgood33\\Php_Db\\' =>
array (
0 => __DIR__ . '/..' . '/godsgood33/php-db/src',
),
'Complex\\' =>
array (
0 => __DIR__ . '/..' . '/markbaker/complex/classes/src',
),
'Cocur\\BackgroundProcess\\' =>
array (
0 => __DIR__ . '/..' . '/cocur/background-process/src',

View File

@ -39,6 +39,152 @@
"unix"
]
},
{
"name": "godsgood33/php-db",
"version": "1.3.1",
"version_normalized": "1.3.1.0",
"source": {
"type": "git",
"url": "https://github.com/godsgood33/php-db.git",
"reference": "cdf01f123c16dcb0b294b3b9013557e2d472f1c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/godsgood33/php-db/zipball/cdf01f123c16dcb0b294b3b9013557e2d472f1c9",
"reference": "cdf01f123c16dcb0b294b3b9013557e2d472f1c9",
"shasum": ""
},
"require": {
"monolog/monolog": "~1.23"
},
"require-dev": {
"phpunit/phpunit": "~7.2"
},
"time": "2018-06-07T18:30:13+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Godsgood33\\Php_Db\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Ryan Prather",
"email": "godsgood33@gmail.com",
"role": "Developer"
}
],
"description": "PHP Database Library",
"homepage": "https://github.com/godsgood33/php-db",
"keywords": [
"database",
"library",
"mysql",
"mysqli"
]
},
{
"name": "markbaker/complex",
"version": "1.4.6",
"version_normalized": "1.4.6.0",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "a78d82ae4e682c3809fc3023d1b0ce654f6ab12b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/a78d82ae4e682c3809fc3023d1b0ce654f6ab12b",
"reference": "a78d82ae4e682c3809fc3023d1b0ce654f6ab12b",
"shasum": ""
},
"require": {
"php": "^5.6.0|^7.0.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
"phpcompatibility/php-compatibility": "^8.0",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "2.*",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^4.8.35|^5.4.0",
"sebastian/phpcpd": "2.*",
"squizlabs/php_codesniffer": "^3.3.0"
},
"time": "2018-07-31T08:38:40+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
},
"files": [
"classes/src/functions/abs.php",
"classes/src/functions/acos.php",
"classes/src/functions/acosh.php",
"classes/src/functions/acot.php",
"classes/src/functions/acoth.php",
"classes/src/functions/acsc.php",
"classes/src/functions/acsch.php",
"classes/src/functions/argument.php",
"classes/src/functions/asec.php",
"classes/src/functions/asech.php",
"classes/src/functions/asin.php",
"classes/src/functions/asinh.php",
"classes/src/functions/atan.php",
"classes/src/functions/atanh.php",
"classes/src/functions/conjugate.php",
"classes/src/functions/cos.php",
"classes/src/functions/cosh.php",
"classes/src/functions/cot.php",
"classes/src/functions/coth.php",
"classes/src/functions/csc.php",
"classes/src/functions/csch.php",
"classes/src/functions/exp.php",
"classes/src/functions/inverse.php",
"classes/src/functions/ln.php",
"classes/src/functions/log2.php",
"classes/src/functions/log10.php",
"classes/src/functions/negative.php",
"classes/src/functions/pow.php",
"classes/src/functions/rho.php",
"classes/src/functions/sec.php",
"classes/src/functions/sech.php",
"classes/src/functions/sin.php",
"classes/src/functions/sinh.php",
"classes/src/functions/sqrt.php",
"classes/src/functions/tan.php",
"classes/src/functions/tanh.php",
"classes/src/functions/theta.php",
"classes/src/operations/add.php",
"classes/src/operations/subtract.php",
"classes/src/operations/multiply.php",
"classes/src/operations/divideby.php",
"classes/src/operations/divideinto.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
]
},
{
"name": "monolog/monolog",
"version": "1.23.0",
@ -121,36 +267,62 @@
},
{
"name": "pacificsec/cpe",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://github.com/pacificsec/cpe.git",
"reference": "3d78d66fc4ea249b6f353a7c48f426835a792d11"
"reference": "52cc49e04388ba00493be634287f6ce3efb30afc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pacificsec/cpe/zipball/3d78d66fc4ea249b6f353a7c48f426835a792d11",
"reference": "3d78d66fc4ea249b6f353a7c48f426835a792d11",
"url": "https://api.github.com/repos/pacificsec/cpe/zipball/52cc49e04388ba00493be634287f6ce3efb30afc",
"reference": "52cc49e04388ba00493be634287f6ce3efb30afc",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2018-08-22T17:55:09+00:00",
"type": "library",
"installation-source": "dist",
"notification-url": "https://packagist.org/downloads/"
"installation-source": "source",
"autoload": {
"psr-4": {
"PacificSec\\CPE\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Franco",
"email": "antonio.franco@pacificsec.com"
}
],
"description": "CPE: Common Platform Enumeration for PHP",
"homepage": "https://github.com/pacificsec/cpe",
"keywords": [
"cpe",
"cve",
"pacificsec",
"security"
]
},
{
"name": "phpoffice/phpspreadsheet",
"version": "1.2.1",
"version_normalized": "1.2.1.0",
"version": "1.4.0",
"version_normalized": "1.4.0.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "36acc372875c4d894dc093825ce4f62209db5a76"
"reference": "125f462a718956f37d81305ca0df4f17cef0f3b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/36acc372875c4d894dc093825ce4f62209db5a76",
"reference": "36acc372875c4d894dc093825ce4f62209db5a76",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/125f462a718956f37d81305ca0df4f17cef0f3b9",
"reference": "125f462a718956f37d81305ca0df4f17cef0f3b9",
"shasum": ""
},
"require": {
@ -166,6 +338,7 @@
"ext-xmlwriter": "*",
"ext-zip": "*",
"ext-zlib": "*",
"markbaker/complex": "^1.4.1",
"php": "^5.6|^7.0",
"psr/simple-cache": "^1.0"
},
@ -175,7 +348,7 @@
"jpgraph/jpgraph": "^4.0",
"mpdf/mpdf": "^7.0.0",
"phpunit/phpunit": "^5.7",
"squizlabs/php_codesniffer": "^2.7",
"squizlabs/php_codesniffer": "^3.3",
"tecnickcom/tcpdf": "^6.2"
},
"suggest": {
@ -184,7 +357,7 @@
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnick.com/tcpdf": "Option for rendering PDF with PDF Writer"
},
"time": "2018-04-10T03:53:16+00:00",
"time": "2018-08-06T02:58:06+00:00",
"type": "library",
"installation-source": "source",
"autoload": {

View File

@ -0,0 +1,17 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

View File

@ -0,0 +1,4 @@
.settings/
.buildpath
code-coverage/
/vendor/

View File

@ -0,0 +1,26 @@
checks:
php: true
filter:
paths: ["src/*"]
tools:
external_code_coverage:
timeout: 600
php_sim: true
php_pdepend: true
php_analyzer: true
php_cs_fixer: true
build:
nodes:
analysis:
tests:
override:
- php-scrutinizer-run
build_failure_conditions:
- 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed
- 'issues.severity(>= MAJOR).new.exists' # New issues of major or higher severity
- 'project.metric_change("scrutinizer.test_coverage", < 0)' # Code Coverage decreased from previous inspection
- 'patches.label("Unused Use Statements").new.exists' # No new unused imports patches allowed

201
inc/vendor/godsgood33/php-db/LICENSE vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

BIN
inc/vendor/godsgood33/php-db/README.md vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,37 @@
{
"require" : {
"monolog/monolog" : "~1.23"
},
"name" : "godsgood33/php-db",
"description" : "PHP Database Library",
"homepage" : "https://github.com/godsgood33/php-db",
"license" : "Apache-2.0",
"minimum-stability" : "beta",
"authors" : [{
"name" : "Ryan Prather",
"email" : "godsgood33@gmail.com",
"role" : "Developer"
}
],
"support" : {
"source" : "https://github.com/godsgood33/php-db"
},
"autoload" : {
"psr-4" : {
"Godsgood33\\Php_Db\\" : "src"
}
},
"type" : "library",
"keywords" : [
"database",
"library",
"mysql",
"mysqli"
],
"config" : {
"vendor-dir" : "vendor"
},
"require-dev" : {
"phpunit/phpunit" : "~7.2"
}
}

1549
inc/vendor/godsgood33/php-db/composer.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,136 @@
{
"tables": [
{
"schema": "db",
"name": "settings",
"primary_key": [
"id"
],
"unique": [
"meta_key"
],
"fields": [
{
"name": "id",
"dataType": "int(11)",
"type": 3,
"length": 11,
"values": [],
"ai": true,
"nn": true,
"default": ""
},
{
"name": "meta_key",
"dataType": "varchar(100)",
"type": 253,
"length": 100,
"values": [],
"ai": false,
"nn": true,
"default": ""
},
{
"name": "meta_value",
"dataType": "mediumtext",
"type": 250,
"length": null,
"values": [],
"ai": false,
"nn": false,
"default": null
}
]
},
{
"schema": "db",
"name": "test",
"primary_key": [
"id",
"fk"
],
"fields": [
{
"name": "id",
"dataType": "int(11)",
"type": 3,
"length": 11,
"values": [],
"ai": true,
"nn": true,
"default": ""
},
{
"name": "fk",
"dataType": "int(11)",
"type": 3,
"length": 11,
"values": [],
"ai": false,
"nn": true,
"default": ""
},
{
"name": "default",
"dataType": "tinyint(1)",
"type": 1,
"length": 1,
"values": [],
"ai": false,
"nn": false,
"default": "0"
},
{
"name": "enum",
"dataType": "enum",
"type": 247,
"length": null,
"values": [
"1",
"2"
],
"ai": false,
"nn": false,
"default": "1"
}
],
"constraints": [
{
"id": "con_1",
"local": "fk",
"schema": "db",
"table": "test",
"field": "id",
"update": null,
"delete": null
}
],
"index": [
{
"id": "default_idx",
"type": "index",
"ref": "default"
}
]
},
{
"schema": "db",
"name": "test2",
"primary_key": [
"id"
],
"fields": [
{
"name": "id",
"dataType": "int(11)",
"type": 3,
"length": 11,
"values": [],
"ai": true,
"nn": true,
"default": ""
}
]
}
]
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="tests/bootstrap.php"
colors="true"
verbose="true">
<testsuites>
<testsuite name="Tests">
<directory suffix=".php">tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="false">
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,50 @@
<?php
/**
* Constant with database server to connect to
*
* @var string
*/
define('PHP_DB_SERVER', '{IP|hostname}');
/**
* Constant with database user to connect with
*
* @var string
*/
define('PHP_DB_USER', '{username}');
/**
* Constant with database password to connect with
*
* @var string
*/
define('PHP_DB_PWD', '{password}');
/**
* Constant with database schema to connect to
*
* @var string
*/
define('PHP_DB_SCHEMA', '{schema}');
/**
* Constant to define that we want to return an object
*
* @var int
*/
define('MYSQLI_OBJECT', 4);
/**
* Constant to return consistent date format
*
* @var string
*/
define('MYSQL_DATE', 'Y-m-d');
/**
* Constant to return consistent datetime format
*
* @var string
*/
define('MYSQL_DATETIME', 'Y-m-d H:i:s');

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,794 @@
<?php
use Godsgood33\Php_Db\Database;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;
require_once 'TestClass.php'; // class with _escape method
require_once 'TestClass2.php';
// class without _escape method
/**
* @coversDefaultClass Database
*/
final class DatabaseTest extends TestCase
{
private $db;
public function setUp()
{
$this->db = new Database(realpath(__DIR__));
// Database::$autorun = true;
}
public function testCanCreateDatabaseInstance()
{
$this->assertInstanceOf("Godsgood33\Php_Db\Database", $this->db);
}
public function testGetSchema()
{
$schema = $this->db->getSchema();
$this->assertEquals("db", $schema);
}
public function testSetSchemaWithNonExistentSchema()
{
$ret = $this->db->setSchema("george");
$this->assertFalse($ret);
}
public function testDatabaseConnection()
{
$this->assertTrue($this->db->isConnected());
}
public function testPassInMysqliConnection()
{
$conn = new mysqli(PHP_DB_SERVER, PHP_DB_USER, PHP_DB_PWD, PHP_DB_SCHEMA);
if ($conn->connect_errno) {
fwrite(STDOUT, $conn->connect_error);
}
$this->db = new Database(realpath(__DIR__), $conn);
$this->assertInstanceOf("Godsgood33\Php_Db\Database", $this->db);
}
public function testSetLogLevel()
{
$this->db->setLogLevel(Logger::DEBUG);
$this->assertEquals(Logger::DEBUG, $this->db->getLogLevel());
}
/**
* @expectedException TypeError
*/
public function testSelectWithInvalidTableName()
{
$this->db->select(new stdClass());
}
public function testSelectWithNoParameters()
{
// query table with NO parameters
$this->db->select("test");
$this->assertEquals("SELECT * FROM test", $this->db->getSql());
}
public function testSelectWithNullFieldParameter()
{
// query table with null fields parameter
$this->db->select("test", null);
$this->assertEquals("SELECT * FROM test", $this->db->getSql());
}
public function testSelectWithOneArrayParameter()
{
// query table with one parameter
$this->db->select("test", [
'id'
]);
$this->assertEquals("SELECT `id` FROM test", $this->db->getSql());
}
public function testSelectWithTwoArrayParameters()
{
// query table with 2 parameters
$this->db->select("test", [
'id',
'name'
]);
$this->assertEquals("SELECT `id`,`name` FROM test", $this->db->getSql());
}
public function testSelectWithOneStringParameter()
{
// query table with string parameter
$this->db->select("test", 'id');
$this->assertEquals("SELECT id FROM test", $this->db->getSql());
}
/**
* @expectedException InvalidArgumentException
*/
public function testSelectWithStdClassParameter()
{
// query table with object parameter
$this->db->select("test", new stdClass());
$this->assertEquals("SELECT FROM test", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testSelectWithNullWhereParameter()
{
// query table with null where parameter
$this->db->select("test", 'id', null);
$this->assertEquals("SELECT id FROM test", $this->db->getSql());
}
public function testSelectWithEmptyArrayWhereParameter()
{
// query table with empty array where paramter
$this->db->select("test", 'id', []);
$this->assertEquals("SELECT id FROM test", $this->db->getSql());
}
public function testSelectWithImcompleteWhereArrayParameter()
{
// query with incomplete WHERE clause
$this->db->select("test", 'id', [
[
'field' => 'id'
]
]);
$this->assertEquals("SELECT id FROM test", $this->db->getSql());
}
public function testGroupWithString()
{
// $this->markTestIncomplete();
// query with single group by string
$sql = $this->db->groups('name');
$this->assertEquals(" GROUP BY name", $sql);
}
public function testGroupWithArray()
{
// query with array group by string
$sql = $this->db->groups([
'name',
'id'
]);
$this->assertEquals(" GROUP BY name, id", $sql);
}
/**
* @expectedException Exception
*/
public function testGroupWrongUnknownDataType()
{
// $this->markTestIncomplete();
// query group with invalid datatype (stdClass) should throw Exception
$this->db->groups(new stdClass());
}
public function testOrderWithString()
{
// $this->markTestIncomplete();
// query with single name order parameter
$sql = $this->db->order("name");
$this->assertEquals(" ORDER BY name", $sql);
}
public function testOrderWithArray()
{
// query with order array
$sql = $this->db->order([
[
'field' => 'id',
'sort' => 'ASC'
],
[
'field' => 'name',
'sort' => 'DESC'
]
]);
$this->assertEquals(" ORDER BY id ASC, name DESC", $sql);
}
public function testOrderWithObject()
{
// query with invalid datatype (stdClass) will return empty string
$sql = $this->db->order(new stdClass());
$this->assertEquals("", $sql);
}
public function testFlags()
{
// $this->markTestIncomplete();
// query flags with all parameters
$sql = $this->db->flags([
'group' => 'name',
'order' => 'name',
'having' => [
[
'field' => 'id',
'op' => '=',
'value' => 1
]
],
'limit' => '10',
'start' => '5'
]);
$this->assertEquals(" GROUP BY name HAVING `id` = '1' ORDER BY name LIMIT 5,10", $sql);
}
public function testCreateTemporaryTable()
{
$this->db->select("test");
$this->db->createTable('test2', true);
$this->assertEquals("CREATE TEMPORARY TABLE IF NOT EXISTS test2 AS (SELECT * FROM test)", $this->db->getSql());
}
public function testCreateTable()
{
// Database::$autorun = false;
$this->db->createTable('test', false, $this->db->select("test"));
$this->assertEquals("CREATE TABLE IF NOT EXISTS test AS (SELECT * FROM test)", $this->db->getSql());
// Database::$autorun = true;
}
public function testCreateTableWithArrayParameter()
{
$this->db->createTable("test", true, [
[
'field' => 'id',
'datatype' => 'int(11)',
'option' => 'PRIMARY KEY'
],
[
'field' => 'name',
'datatype' => 'varchar(100)',
'default' => null
],
[
'field' => 'email',
'datatype' => 'varchar(100)',
'default' => ''
]
]);
$this->assertEquals("CREATE TEMPORARY TABLE IF NOT EXISTS test (`id` int(11) PRIMARY KEY,`name` varchar(100),`email` varchar(100) DEFAULT '')", $this->db->getSql());
}
public function testCreateTableJson()
{
$json = json_decode(file_get_contents(dirname(dirname(__FILE__)) . "/examples/create_table_json.json"));
$this->db->createTableJson($json->tables[0]);
$this->assertEquals("CREATE TABLE IF NOT EXISTS `settings` (`id` int(11) AUTO_INCREMENT NOT NULL,`meta_key` varchar(100) NOT NULL,`meta_value` mediumtext DEFAULT NULL, UNIQUE(`meta_key`), PRIMARY KEY(`id`))", $this->db->getSql());
}
public function testCreateTableJson2()
{
$json = json_decode(file_get_contents(dirname(dirname(__FILE__)) . "/examples/create_table_json.json"));
$this->db->createTableJson($json->tables[1]);
$this->assertEquals("CREATE TABLE IF NOT EXISTS `test` (`id` int(11) AUTO_INCREMENT NOT NULL,`fk` int(11) NOT NULL,`default` tinyint(1) DEFAULT '0',`enum` enum('1','2') DEFAULT '1', INDEX `default_idx` (`default`), CONSTRAINT `con_1` FOREIGN KEY (`fk`) REFERENCES `db`.`test` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, PRIMARY KEY(`id`,`fk`))", $this->db->getSql());
}
public function testCreateTableJson3()
{
$json = json_decode(file_get_contents(dirname(dirname(__FILE__)) . "/examples/create_table_json.json"));
$this->db->createTableJson($json->tables[2]);
$this->assertEquals("CREATE TABLE IF NOT EXISTS `test2` (`id` int(11) AUTO_INCREMENT NOT NULL, PRIMARY KEY(`id`))", $this->db->getSql());
}
public function testTableExists()
{
$tbl_count = $this->db->tableExists('db', 'settings');
$this->assertEquals(1, $tbl_count);
}
public function testMultipleTableExists()
{
$tbl_count = $this->db->tableExists('db', 'test%');
$this->assertEquals(2, $tbl_count);
}
public function testTableNotPresent()
{
$tbl_not_present = $this->db->tableExists('db', "users");
$this->assertFalse($tbl_not_present);
}
public function testAlterTableAddColumn()
{
$new = new stdClass();
$new->name = 'newCol';
$new->dataType = 'tinyint(1)';
$new->nn = false;
$new->default = null;
$this->db->alterTable('test', Database::ADD_COLUMN, $new);
$this->assertEquals("ALTER TABLE test ADD COLUMN `newCol` tinyint(1) DEFAULT NULL", $this->db->getSql());
}
public function testAlterTableModifyColumn()
{
$mod = new stdClass();
$mod->name = 'default';
$mod->new_name = 'default2';
$mod->dataType = 'int(1)';
$mod->nn = true;
$mod->default = 1;
$this->db->alterTable("test", Database::MODIFY_COLUMN, $mod);
$this->assertEquals("ALTER TABLE test MODIFY COLUMN `default` `default2` int(1) NOT NULL DEFAULT '1'", $this->db->getSql());
}
public function testAlterTableDropColumn()
{
$drop = new stdClass();
$drop->name = 'newCol';
$this->db->alterTable("test", Database::DROP_COLUMN, [
$drop
]);
$this->assertEquals("ALTER TABLE test DROP COLUMN `newCol`", $this->db->getSql());
}
public function testSelectCountWithNoParameters()
{
$this->db->selectCount("test");
$this->assertEquals("SELECT COUNT(1) AS 'count' FROM test", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testSelectCountWithStdClassParameterForTable()
{
$this->db->selectCount(new stdClass());
}
public function testSelectCountWithArrayWhereParameter()
{
$this->db->selectCount("test", [
[
'field' => 'name',
'value' => 'Ed'
]
], [
'joins' => [
"JOIN settings s ON s.id = test.id"
]
]);
$this->assertEquals("SELECT COUNT(1) AS 'count' FROM test JOIN settings s ON s.id = test.id WHERE `name` = 'Ed'", $this->db->getSql());
}
public function testInsertWithOneElementArrayParameter()
{
// query with one parameter
$this->db->insert("test", [
'id' => 1
]);
$this->assertEquals("INSERT INTO test (`id`) VALUES ('1')", $this->db->getSql());
}
public function testInsertWithTwoElementArrayParameter()
{
// query with 2 parameters
$this->db->insert("test", [
'id' => 1,
'name' => 'Ed'
], true);
$this->assertEquals("INSERT IGNORE INTO test (`id`,`name`) VALUES ('1','Ed')", $this->db->getSql());
}
public function testInsertWithSelectStatement()
{
// insert query using SELECT statement
$this->db->insert("test", "SELECT id FROM settings");
$this->assertEquals("INSERT INTO test SELECT id FROM settings", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testInsertInvalidTableNameDataType()
{
$this->db->insert(new stdClass());
}
/**
* @expectedException Error
*/
public function testInsertInvalidParameterDataType()
{
$this->db->insert("test", new stdClass());
}
public function testEInsert()
{
// extended insert query with fields and 2 items
$this->db->extendedInsert("test", [
'id',
'name'
], [
[
1,
'Ed'
],
[
2,
'Frank'
]
]);
$this->assertEquals("INSERT INTO test (`id`,`name`) VALUES ('1','Ed'),('2','Frank')", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testEInsertInvalidTableNameDatatype()
{
$this->db->extendedInsert(new stdClass(), [], []);
}
/**
* @expectedException Error
*/
public function testEInsertDifferentFieldValuePairs()
{
$this->db->extendedInsert('test', [
'id',
'name'
], [
[
1
],
[
2
]
]);
}
/**
* @expectedException Error
*/
public function testEInsertDifferentFieldValuePairs2()
{
$this->db->extendedInsert('test', [
'id',
'name'
], [
[
1,
'Ed'
],
[
2
]
]);
}
public function testUpdateWithOneElementArrayParameter()
{
$this->db->update('test', [
'name' => 'Frank'
]);
$this->assertEquals("UPDATE test SET `name`='Frank'", $this->db->getSql());
}
public function testUpdateWithOneElementAndWhereArray()
{
$this->db->update('test', [
'name' => 'Frank'
], [
[
'field' => 'id',
'value' => 1
]
]);
$this->assertEquals("UPDATE test SET `name`='Frank' WHERE `id` = '1'", $this->db->getSql());
}
public function testUpdateWithOneElementAndJoinClause()
{
$this->db->update('test t', [
't.name' => 'Frank'
], [], [
'joins' => [
"JOIN settings s ON s.id=t.id"
]
]);
$this->assertEquals("UPDATE test t JOIN settings s ON s.id=t.id SET t.name='Frank'", $this->db->getSql());
}
public function testUpdateWithOneElementAndLimitClause()
{
$this->db->update('test', [
'name' => 'Frank'
], [], [
'limit' => 1
]);
$this->assertEquals("UPDATE test SET `name`='Frank' LIMIT 1", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testUpdateInvalidTableNameDatatype()
{
$this->db->update(new stdClass(), []);
}
public function testEUpdateWithArrayList()
{
$this->db->extendedUpdate("test", "settings", "id", [
'name'
]);
$this->assertEquals("UPDATE test tbu INNER JOIN settings o USING (id) SET tbu.`name` = o.`name`", $this->db->getSql());
}
public function testEUpdateWithStringList()
{
$this->db->extendedUpdate("test", "settings", "id", "name");
$this->assertEquals("UPDATE test tbu INNER JOIN settings o USING (id) SET tbu.`name` = o.`name`", $this->db->getSql());
}
/**
* @expectedException Exception
*/
public function testEUpdateInvalidParamDatatype()
{
$this->db->extendedUpdate('test', 'settings', 'id', new stdClass());
}
public function testReplace()
{
$this->db->replace("test", [
'id' => 1
]);
$this->assertEquals("REPLACE INTO test (`id`) VALUES ('1')", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testReplaceInvalidTableNameDatatype()
{
$this->db->replace(new stdClass(), []);
}
public function testEReplace()
{
$this->db->extendedReplace("test", [
'id',
'name'
], [
[
1,
'Ed'
],
[
2,
'Frank'
]
]);
$this->assertEquals("REPLACE INTO test (`id`,`name`) VALUES ('1','Ed'),('2','Frank')", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testEReplaceInvalidTableNameDatatype()
{
$this->db->extendedReplace(new stdClass(), [], []);
}
public function testFieldExists()
{
$id_exists = $this->db->fieldExists('test', 'id');
$this->assertTrue($id_exists);
}
public function testFieldDoesNotExist()
{
$phone_not_exists = $this->db->fieldExists('test', 'phone');
$this->assertFalse($phone_not_exists);
}
public function testFieldData()
{
$id = new stdClass();
$id->name = 'id';
$id->orgname = 'id';
$id->table = 'test2';
$id->orgtable = 'test2';
$id->def = null;
$id->db = 'db';
$id->catalog = 'def';
$id->max_length = 0;
$id->length = 11;
$id->charsetnr = 63;
$id->flags = 49667;
$id->type = 3;
$id->decimals = 0;
// query all fields in table
$fd = $this->db->fieldData("test2");
$this->assertEquals([
'id' => $id
], $fd);
// query single field in table
$fd = $this->db->fieldData('test2', 'id');
$this->assertEquals([
'id' => $id
], $fd);
// query array of fields in table
$fd = $this->db->fieldData('test2', [
'id'
]);
$this->assertEquals([
'id' => $id
], $fd);
// invalid datatype for field name
$fd = $this->db->fieldData('test2', new stdClass());
$this->assertEquals(null, $fd);
}
public function testEscapeDontEscapeNow()
{
// $this->markTestIncomplete();
$ret = $this->db->_escape('NOW()', false);
$this->assertEquals("NOW()", $ret);
}
public function testEscapeDontEscapeBackticks()
{
$ret = $this->db->_escape("t.`id`", false);
$this->assertEquals("t.`id`", $ret);
}
public function testEscapeEscapeDateTime()
{
$dt = new DateTime("2017-01-01 00:00:00");
$ret = $this->db->_escape($dt);
$this->assertEquals("'2017-01-01 00:00:00'", $ret);
}
public function testEscapeBoolean()
{
$ret = $this->db->_escape(true);
$this->assertEquals("'1'", $ret);
}
public function testEscapeClassWithEscapeMethod()
{
$tc = new TestClass();
$tc->var = "test's";
$ret = $this->db->_escape($tc);
$this->assertEquals("test\'s", $ret);
}
public function testEscapeUnknownClassToEscape()
{
// $this->markTestIncomplete();
$tc2 = new TestClass2();
$tc2->var = "test";
$ret = $this->db->_escape($tc2);
$this->assertEquals("", $ret);
}
public function testDeleteBasic()
{
$this->db->delete("test");
$this->assertEquals("DELETE FROM test", $this->db->getSql());
}
public function testDeleteWithWhereClause()
{
$this->db->delete('test', [
'id'
], [
[
'field' => 'id',
'op' => '=',
'value' => 1
]
]);
$this->assertEquals("DELETE id FROM test WHERE `id` = '1'", $this->db->getSql());
}
public function testDeleteWithJoin()
{
$this->db->delete('test t', [], [], [
'joins' => "JOIN settings s ON s.id=t.id"
]);
$this->assertEquals("DELETE FROM test t JOIN settings s ON s.id=t.id", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testDeleteInvalidTableNameDatatype()
{
$this->db->delete(new stdClass());
}
public function testTruncate()
{
$this->db->truncate('test');
$this->assertEquals("TRUNCATE TABLE test", $this->db->getSql());
}
/**
* @expectedException TypeError
*/
public function testTruncateInvalidTableNameDatatype()
{
$this->db->truncate(new stdClass());
}
public function testDropSettingsTable()
{
// Database::$autorun = false;
$sql = $this->db->drop("settings");
$this->assertEquals("DROP TABLE IF EXISTS `settings`", $sql);
// Database::$autorun = true;
}
public function testDropTestTable()
{
// Database::$autorun = false;
$sql = $this->db->drop("test");
$this->assertEquals("DROP TABLE IF EXISTS `test`", $sql);
// Database::$autorun = true;
}
public function testDropView()
{
// Database::$autorun = false;
$sql = $this->db->drop("test", "view");
$this->assertEquals("DROP VIEW IF EXISTS `test`", $sql);
// Database::$autorun = true;
}
/**
* @expectedException TypeError
*/
public function testDropInvalidTableNameDatatype()
{
$this->db->drop(new stdClass());
}
/**
* @expectedException TypeError
*/
public function testDropInvalidTypeDatatype()
{
$this->db->drop('test', new stdClass());
}
public function testSetSchema()
{
// set the schema and validate that it is what we set it to
$this->db->setSchema("test");
$row = $this->db->query("SELECT DATABASE()");
$this->assertEquals("test", $row->fetch_array()[0]);
}
}

View File

@ -0,0 +1,24 @@
<?php
class TestClass
{
var $var;
public function _escape()
{
return str_replace([
"\n",
"\r",
"\\",
"'",
'"'
], [
"\\n",
"\\r",
"\\\\",
"\'",
'\"'
], $this->var);
}
}

View File

@ -0,0 +1,5 @@
<?php
class TestClass2 {
var $var;
}

View File

@ -0,0 +1,3 @@
<?php
require dirname(dirname(__FILE__)) . "/vendor/autoload.php";
require dirname(dirname(__FILE__)) . "/src/Database.php";

155
inc/vendor/markbaker/complex/README.md vendored Normal file
View File

@ -0,0 +1,155 @@
PHPComplex
==========
---
PHP Class for handling Complex numbers
Master: [![Build Status](https://travis-ci.org/MarkBaker/PHPComplex.png?branch=master)](http://travis-ci.org/MarkBaker/PHPComplex)
Develop: [![Build Status](https://travis-ci.org/MarkBaker/PHPComplex.png?branch=develop)](http://travis-ci.org/MarkBaker/PHPComplex)
---
The library currently provides the following operations:
- addition
- subtraction
- multiplication
- division
- division by
- division into
together with functions for
- theta (polar theta angle)
- rho (polar distance/radius)
- conjugate
* negative
- inverse (1 / complex)
- cos (cosine)
- acos (inverse cosine)
- cosh (hyperbolic cosine)
- acosh (inverse hyperbolic cosine)
- sin (sine)
- asin (inverse sine)
- sinh (hyperbolic sine)
- asinh (inverse hyperbolic sine)
- sec (secant)
- asec (inverse secant)
- sech (hyperbolic secant)
- asech (inverse hyperbolic secant)
- csc (cosecant)
- acsc (inverse cosecant)
- csch (hyperbolic secant)
- acsch (inverse hyperbolic secant)
- tan (tangent)
- atan (inverse tangent)
- tanh (hyperbolic tangent)
- atanh (inverse hyperbolic tangent)
- cot (cotangent)
- acot (inverse cotangent)
- coth (hyperbolic cotangent)
- acoth (inverse hyperbolic cotangent)
- sqrt (square root)
- exp (exponential)
- ln (natural log)
- log10 (base-10 log)
- log2 (base-2 log)
- pow (raised to the power of a real number)
---
# Usage
To create a new complex object, you can provide either the real, imaginary and suffix parts as individual values, or as an array of values passed passed to the constructor; or a string representing the value. e.g
```
$real = 1.23;
$imaginary = -4.56;
$suffix = 'i';
$complexObject = new Complex\Complex($real, $imaginary, $suffix);
```
or
```
$real = 1.23;
$imaginary = -4.56;
$suffix = 'i';
$arguments = [$real, $imaginary, $suffix];
$complexObject = new Complex\Complex($arguments);
```
or
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
```
Complex objects are immutable: whenever you call a method or pass a complex value to a function that returns a complex value, a new Complex object will be returned, and the original will remain unchanged.
This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Complex result).
## Performing Mathematical Operations
To perform mathematical operations with Complex values, you can call the appropriate method against a complex value, passing other values as arguments
```
$complexString1 = '1.23-4.56i';
$complexString2 = '2.34+5.67i';
$complexObject = new Complex\Complex($complexString1);
echo $complexObject->add($complexString2);
```
or pass all values to the appropriate function
```
$complexString1 = '1.23-4.56i';
$complexString2 = '2.34+5.67i';
echo Complex\add($complexString1, $complexString2);
```
If you want to perform the same operation against multiple values (e.g. to add three or more complex numbers), then you can pass multiple arguments to any of the operations.
You can pass these arguments as Complex objects, or as an array or string that will parse to a complex object.
## Using functions
When calling any of the available functions for a complex value, you can either call the relevant method for the Complex object
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
echo $complexObject->sinh();
```
or you can call the function as you would in procedural code, passing the Complex object as an argument
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
echo Complex\sinh($complexObject);
```
When called procedurally using the function, you can pass in the argument as a Complex object, or as an array or string that will parse to a complex object.
```
$complexString = '1.23-4.56i';
echo Complex\sinh($complexString);
```
In the case of the `pow()` function (the only implemented function that requires an additional argument) you need to pass both arguments when calling the function procedurally
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
echo Complex\pow($complexObject, 2);
```
or pass the additional argument when calling the method
```
$complexString = '1.23-4.56i';
$complexObject = new Complex\Complex($complexString);
echo $complexObject->pow(2);
```

View File

@ -0,0 +1,53 @@
<?php
namespace Complex;
/**
*
* Autoloader for Complex classes
*
* @package Complex
* @copyright Copyright (c) 2014 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
*/
class Autoloader
{
/**
* Register the Autoloader with SPL
*
*/
public static function Register()
{
if (function_exists('__autoload')) {
// Register any existing autoloader function with SPL, so we don't get any clashes
spl_autoload_register('__autoload');
}
// Register ourselves with SPL
return spl_autoload_register(['Complex\Autoloader', 'Load']);
}
/**
* Autoload a class identified by name
*
* @param string $pClassName Name of the object to load
*/
public static function Load($pClassName)
{
if ((class_exists($pClassName, false)) || (strpos($pClassName, 'Complex\\') !== 0)) {
// Either already loaded, or not a Complex class request
return false;
}
$pClassFilePath = __DIR__ . DIRECTORY_SEPARATOR .
'src' . DIRECTORY_SEPARATOR .
str_replace('Complex\\', '', $pClassName) .
'.php';
if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
// Can't load
return false;
}
require($pClassFilePath);
}
}

View File

@ -0,0 +1,38 @@
<?php
include_once __DIR__ . '/Autoloader.php';
\Complex\Autoloader::Register();
abstract class FilesystemRegexFilter extends RecursiveRegexIterator
{
protected $regex;
public function __construct(RecursiveIterator $it, $regex)
{
$this->regex = $regex;
parent::__construct($it, $regex);
}
}
class FilenameFilter extends FilesystemRegexFilter
{
// Filter files against the regex
public function accept()
{
return (!$this->isFile() || preg_match($this->regex, $this->getFilename()));
}
}
$srcFolder = __DIR__ . DIRECTORY_SEPARATOR . 'src';
$srcDirectory = new RecursiveDirectoryIterator($srcFolder);
$filteredFileList = new FilenameFilter($srcDirectory, '/(?:php)$/i');
$filteredFileList = new FilenameFilter($filteredFileList, '/^(?!.*(Complex|Exception)\.php).*$/i');
foreach (new RecursiveIteratorIterator($filteredFileList) as $file) {
if ($file->isFile()) {
include_once $file;
}
}

View File

@ -0,0 +1,387 @@
<?php
/**
*
* Class for the management of Complex numbers
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Complex Number object.
*
* @package Complex
*
* @method float abs()
* @method Complex acos()
* @method Complex acosh()
* @method Complex acot()
* @method Complex acoth()
* @method Complex acsc()
* @method Complex acsch()
* @method float argument()
* @method Complex asec()
* @method Complex asech()
* @method Complex asin()
* @method Complex asinh()
* @method Complex atan()
* @method Complex atanh()
* @method Complex conjugate()
* @method Complex cos()
* @method Complex cosh()
* @method Complex cot()
* @method Complex coth()
* @method Complex csc()
* @method Complex csch()
* @method Complex exp()
* @method Complex inverse()
* @method Complex ln()
* @method Complex log2()
* @method Complex log10()
* @method Complex negative()
* @method Complex pow(int|float $power)
* @method float rho()
* @method Complex sec()
* @method Complex sech()
* @method Complex sin()
* @method Complex sinh()
* @method Complex sqrt()
* @method Complex tan()
* @method Complex tanh()
* @method float theta()
* @method Complex add(...$complexValues)
* @method Complex subtract(...$complexValues)
* @method Complex multiply(...$complexValues)
* @method Complex divideby(...$complexValues)
* @method Complex divideinto(...$complexValues)
*/
class Complex
{
/**
* @constant Euler's Number.
*/
const EULER = 2.7182818284590452353602874713526624977572;
/**
* @constant Regexp to split an input string into real and imaginary components and suffix
*/
const NUMBER_SPLIT_REGEXP =
'` ^
( # Real part
[-+]?(\d+\.?\d*|\d*\.?\d+) # Real value (integer or float)
([Ee][-+]?[0-2]?\d{1,3})? # Optional real exponent for scientific format
)
( # Imaginary part
[-+]?(\d+\.?\d*|\d*\.?\d+) # Imaginary value (integer or float)
([Ee][-+]?[0-2]?\d{1,3})? # Optional imaginary exponent for scientific format
)?
( # Imaginary part is optional
([-+]?) # Imaginary (implicit 1 or -1) only
([ij]?) # Imaginary i or j - depending on whether mathematical or engineering
)
$`uix';
/**
* @var float $realPart The value of of this complex number on the real plane.
*/
protected $realPart = 0.0;
/**
* @var float $imaginaryPart The value of of this complex number on the imaginary plane.
*/
protected $imaginaryPart = 0.0;
/**
* @var string $suffix The suffix for this complex number (i or j).
*/
protected $suffix;
/**
* Validates whether the argument is a valid complex number, converting scalar or array values if possible
*
* @param mixed $complexNumber The value to parse
* @return array
* @throws Exception If the argument isn't a Complex number or cannot be converted to one
*/
private static function parseComplex($complexNumber)
{
// Test for real number, with no imaginary part
if (is_numeric($complexNumber)) {
return [$complexNumber, 0, null];
}
// Fix silly human errors
$complexNumber = str_replace(
['+-', '-+', '++', '--'],
['-', '-', '+', '+'],
$complexNumber
);
// Basic validation of string, to parse out real and imaginary parts, and any suffix
$validComplex = preg_match(
self::NUMBER_SPLIT_REGEXP,
$complexNumber,
$complexParts
);
if (!$validComplex) {
// Neither real nor imaginary part, so test to see if we actually have a suffix
$validComplex = preg_match('/^([\-\+]?)([ij])$/ui', $complexNumber, $complexParts);
if (!$validComplex) {
throw new Exception('Invalid complex number');
}
// We have a suffix, so set the real to 0, the imaginary to either 1 or -1 (as defined by the sign)
$imaginary = 1;
if ($complexParts[1] === '-') {
$imaginary = 0 - $imaginary;
}
return [0, $imaginary, $complexParts[2]];
}
// If we don't have an imaginary part, identify whether it should be +1 or -1...
if (($complexParts[4] === '') && ($complexParts[9] !== '')) {
if ($complexParts[7] !== $complexParts[9]) {
$complexParts[4] = 1;
if ($complexParts[8] === '-') {
$complexParts[4] = -1;
}
} else {
// ... or if we have only the real and no imaginary part
// (in which case our real should be the imaginary)
$complexParts[4] = $complexParts[1];
$complexParts[1] = 0;
}
}
// Return real and imaginary parts and suffix as an array, and set a default suffix if user input lazily
return [
$complexParts[1],
$complexParts[4],
!empty($complexParts[9]) ? $complexParts[9] : 'i'
];
}
public function __construct($realPart = 0.0, $imaginaryPart = null, $suffix = 'i')
{
if ($imaginaryPart === null) {
if (is_array($realPart)) {
// We have an array of (potentially) real and imaginary parts, and any suffix
list ($realPart, $imaginaryPart, $suffix) = array_values($realPart) + [0.0, 0.0, 'i'];
} elseif ((is_string($realPart)) || (is_numeric($realPart))) {
// We've been given a string to parse to extract the real and imaginary parts, and any suffix
list($realPart, $imaginaryPart, $suffix) = self::parseComplex($realPart);
}
}
if ($imaginaryPart <> 0.0 && empty($suffix)) {
$suffix = 'i';
}
// Set parsed values in our properties
$this->realPart = (float) $realPart;
$this->imaginaryPart = (float) $imaginaryPart;
$this->suffix = strtolower($suffix);
}
/**
* Gets the real part of this complex number
*
* @return Float
*/
public function getReal()
{
return $this->realPart;
}
/**
* Gets the imaginary part of this complex number
*
* @return Float
*/
public function getImaginary()
{
return $this->imaginaryPart;
}
/**
* Gets the suffix of this complex number
*
* @return String
*/
public function getSuffix()
{
return $this->suffix;
}
/**
* Returns true if this is a real value, false if a complex value
*
* @return Bool
*/
public function isReal()
{
return $this->imaginaryPart == 0.0;
}
/**
* Returns true if this is a complex value, false if a real value
*
* @return Bool
*/
public function isComplex()
{
return !$this->isReal();
}
public function format()
{
$str = "";
if ($this->imaginaryPart != 0.0) {
if (\abs($this->imaginaryPart) != 1.0) {
$str .= $this->imaginaryPart . $this->suffix;
} else {
$str .= (($this->imaginaryPart < 0.0) ? '-' : '') . $this->suffix;
}
}
if ($this->realPart != 0.0) {
if (($str) && ($this->imaginaryPart > 0.0)) {
$str = "+" . $str;
}
$str = $this->realPart . $str;
}
if (!$str) {
$str = "0.0";
}
return $str;
}
public function __toString()
{
return $this->format();
}
/**
* Validates whether the argument is a valid complex number, converting scalar or array values if possible
*
* @param mixed $complex The value to validate
* @return Complex
* @throws Exception If the argument isn't a Complex number or cannot be converted to one
*/
public static function validateComplexArgument($complex)
{
if (is_scalar($complex) || is_array($complex)) {
$complex = new Complex($complex);
} elseif (!is_object($complex) || !($complex instanceof Complex)) {
throw new Exception('Value is not a valid complex number');
}
return $complex;
}
/**
* Returns the reverse of this complex number
*
* @return Complex
*/
public function reverse()
{
return new Complex(
$this->imaginaryPart,
$this->realPart,
($this->realPart == 0.0) ? null : $this->suffix
);
}
public function invertImaginary()
{
return new Complex(
$this->realPart,
$this->imaginaryPart * -1,
($this->imaginaryPart == 0.0) ? null : $this->suffix
);
}
public function invertReal()
{
return new Complex(
$this->realPart * -1,
$this->imaginaryPart,
($this->imaginaryPart == 0.0) ? null : $this->suffix
);
}
protected static $functions = [
'abs',
'acos',
'acosh',
'acot',
'acoth',
'acsc',
'acsch',
'argument',
'asec',
'asech',
'asin',
'asinh',
'atan',
'atanh',
'conjugate',
'cos',
'cosh',
'cot',
'coth',
'csc',
'csch',
'exp',
'inverse',
'ln',
'log2',
'log10',
'negative',
'pow',
'rho',
'sec',
'sech',
'sin',
'sinh',
'sqrt',
'tan',
'tanh',
'theta',
];
protected static $operations = [
'add',
'subtract',
'multiply',
'divideby',
'divideinto',
];
/**
* Returns the result of the function call or operation
*
* @return Complex|float
* @throws Exception|\InvalidArgumentException
*/
public function __call($functionName, $arguments)
{
$functionName = strtolower(str_replace('_', '', $functionName));
// Test for function calls
if (in_array($functionName, self::$functions)) {
$functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
return $functionName($this, ...$arguments);
}
// Test for operation calls
if (in_array($functionName, self::$operations)) {
$functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
return $functionName($this, ...$arguments);
}
throw new Exception('Function or Operation does not exist');
}
}

View File

@ -0,0 +1,13 @@
<?php
/**
* Exception.
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
class Exception extends \Exception
{
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex abs() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the absolute value (modulus) of a complex number.
* Also known as the rho of the complex number, i.e. the distance/radius
* from the centrepoint to the representation of the number in polar coordinates.
*
* This function is a synonym for rho()
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The absolute (or rho) value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*
* @see rho
*
*/
function abs($complex)
{
return rho($complex);
}

View File

@ -0,0 +1,38 @@
<?php
/**
*
* Function code for the complex acos() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse cosine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse cosine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function acos($complex)
{
$complex = Complex::validateComplexArgument($complex);
$square = clone $complex;
$square = multiply($square, $complex);
$invsqrt = new Complex(1.0);
$invsqrt = subtract($invsqrt, $square);
$invsqrt = sqrt($invsqrt);
$adjust = new Complex(
$complex->getReal() - $invsqrt->getImaginary(),
$complex->getImaginary() + $invsqrt->getReal()
);
$log = ln($adjust);
return new Complex(
$log->getImaginary(),
-1 * $log->getReal()
);
}

View File

@ -0,0 +1,34 @@
<?php
/**
*
* Function code for the complex acosh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic cosine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic cosine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function acosh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal() && ($complex->getReal() > 1)) {
return new Complex(\acosh($complex->getReal()));
}
$acosh = acos($complex)
->reverse();
if ($acosh->getReal() < 0.0) {
$acosh = $acosh->invertReal();
}
return $acosh;
}

View File

@ -0,0 +1,25 @@
<?php
/**
*
* Function code for the complex acot() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse cotangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse cotangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function acot($complex)
{
$complex = Complex::validateComplexArgument($complex);
return atan(inverse($complex));
}

View File

@ -0,0 +1,25 @@
<?php
/**
*
* Function code for the complex acoth() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic cotangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic cotangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function acoth($complex)
{
$complex = Complex::validateComplexArgument($complex);
return atanh(inverse($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex acsc() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse cosecant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse cosecant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function acsc($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return asin(inverse($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex acsch() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic cosecant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic cosecant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function acsch($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return asinh(inverse($complex));
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* Function code for the complex argument() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the argument of a complex number.
* Also known as the theta of the complex number, i.e. the angle in radians
* from the real axis to the representation of the number in polar coordinates.
*
* This function is a synonym for theta()
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The argument (or theta) value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*
* @see theta
*/
function argument($complex)
{
return theta($complex);
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex asec() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse secant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse secant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function asec($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return acos(inverse($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex asech() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic secant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic secant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function asech($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return acosh(inverse($complex));
}

View File

@ -0,0 +1,37 @@
<?php
/**
*
* Function code for the complex asin() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse sine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse sine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function asin($complex)
{
$complex = Complex::validateComplexArgument($complex);
$square = multiply($complex, $complex);
$invsqrt = new Complex(1.0);
$invsqrt = subtract($invsqrt, $square);
$invsqrt = sqrt($invsqrt);
$adjust = new Complex(
$invsqrt->getReal() - $complex->getImaginary(),
$invsqrt->getImaginary() + $complex->getReal()
);
$log = ln($adjust);
return new Complex(
$log->getImaginary(),
-1 * $log->getReal()
);
}

View File

@ -0,0 +1,33 @@
<?php
/**
*
* Function code for the complex asinh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic sine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic sine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function asinh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal() && ($complex->getReal() > 1)) {
return new Complex(\asinh($complex->getReal()));
}
$asinh = clone $complex;
$asinh = $asinh->reverse()
->invertReal();
$asinh = asin($asinh);
return $asinh->reverse()
->invertImaginary();
}

View File

@ -0,0 +1,45 @@
<?php
/**
*
* Function code for the complex atan() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
//include_once 'Math/Complex.php';
//include_once 'Math/ComplexOp.php';
/**
* Returns the inverse tangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse tangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function atan($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\atan($complex->getReal()));
}
$t1Value = new Complex(-1 * $complex->getImaginary(), $complex->getReal());
$uValue = new Complex(1, 0);
$d1Value = clone $uValue;
$d1Value = subtract($d1Value, $t1Value);
$d2Value = add($t1Value, $uValue);
$uResult = $d1Value->divideBy($d2Value);
$uResult = ln($uResult);
return new Complex(
(($uResult->getImaginary() == M_PI) ? -M_PI : $uResult->getImaginary()) * -0.5,
$uResult->getReal() * 0.5,
$complex->getSuffix()
);
}

View File

@ -0,0 +1,38 @@
<?php
/**
*
* Function code for the complex atanh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse hyperbolic tangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse hyperbolic tangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function atanh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
$real = $complex->getReal();
if ($real >= -1.0 && $real <= 1.0) {
return new Complex(\atanh($real));
} else {
return new Complex(\atanh(1 / $real), (($real < 0.0) ? M_PI_2 : -1 * M_PI_2));
}
}
$iComplex = clone $complex;
$iComplex = $iComplex->invertImaginary()
->reverse();
return atan($iComplex)
->invertReal()
->reverse();
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* Function code for the complex conjugate() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the complex conjugate of a complex number
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The conjugate of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function conjugate($complex)
{
$complex = Complex::validateComplexArgument($complex);
return new Complex(
$complex->getReal(),
-1 * $complex->getImaginary(),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,34 @@
<?php
/**
*
* Function code for the complex cos() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the cosine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The cosine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function cos($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\cos($complex->getReal()));
}
return conjugate(
new Complex(
\cos($complex->getReal()) * \cosh($complex->getImaginary()),
\sin($complex->getReal()) * \sinh($complex->getImaginary()),
$complex->getSuffix()
)
);
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex cosh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic cosine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic cosine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function cosh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\cosh($complex->getReal()));
}
return new Complex(
\cosh($complex->getReal()) * \cos($complex->getImaginary()),
\sinh($complex->getReal()) * \sin($complex->getImaginary()),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex cot() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the cotangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The cotangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function cot($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return new Complex(INF);
}
return inverse(tan($complex));
}

View File

@ -0,0 +1,24 @@
<?php
/**
*
* Function code for the complex coth() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic cotangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic cotangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function coth($complex)
{
$complex = Complex::validateComplexArgument($complex);
return inverse(tanh($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex csc() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the cosecant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The cosecant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function csc($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return inverse(sin($complex));
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex csch() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic cosecant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic cosecant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function csch($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return INF;
}
return inverse(sinh($complex));
}

View File

@ -0,0 +1,34 @@
<?php
/**
*
* Function code for the complex exp() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the exponential of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The exponential of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function exp($complex)
{
$complex = Complex::validateComplexArgument($complex);
if (($complex->getReal() == 0.0) && (\abs($complex->getImaginary()) == M_PI)) {
return new Complex(-1.0, 0.0);
}
$rho = \exp($complex->getReal());
return new Complex(
$rho * \cos($complex->getImaginary()),
$rho * \sin($complex->getImaginary()),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex inverse() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the inverse of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The inverse of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function inverse($complex)
{
$complex = clone Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
return $complex->divideInto(1.0);
}

View File

@ -0,0 +1,33 @@
<?php
/**
*
* Function code for the complex ln() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the natural logarithm of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The natural logarithm of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
*/
function ln($complex)
{
$complex = Complex::validateComplexArgument($complex);
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
throw new \InvalidArgumentException();
}
return new Complex(
\log(rho($complex)),
theta($complex),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex log10() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the common logarithm (base 10) of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The common logarithm (base 10) of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
*/
function log10($complex)
{
$complex = Complex::validateComplexArgument($complex);
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
throw new \InvalidArgumentException();
} elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
return new Complex(\log10($complex->getReal()), 0.0, $complex->getSuffix());
}
return ln($complex)
->multiply(\log10(Complex::EULER));
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex log2() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the base-2 logarithm of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The base-2 logarithm of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If the real and the imaginary parts are both zero
*/
function log2($complex)
{
$complex = Complex::validateComplexArgument($complex);
if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
throw new \InvalidArgumentException();
} elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
return new Complex(\log($complex->getReal(), 2), 0.0, $complex->getSuffix());
}
return ln($complex)
->multiply(\log(Complex::EULER, 2));
}

View File

@ -0,0 +1,31 @@
<?php
/**
*
* Function code for the complex negative() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the negative of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The negative value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*
* @see rho
*
*/
function negative($complex)
{
$complex = Complex::validateComplexArgument($complex);
return new Complex(
-1 * $complex->getReal(),
-1 * $complex->getImaginary(),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,40 @@
<?php
/**
*
* Function code for the complex pow() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns a complex number raised to a power.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @param float|integer $power The power to raise this value to
* @return Complex The complex argument raised to the real power.
* @throws Exception If the power argument isn't a valid real
*/
function pow($complex, $power)
{
$complex = Complex::validateComplexArgument($complex);
if (!is_numeric($power)) {
throw new Exception('Power argument must be a real number');
}
if ($complex->getImaginary() == 0.0 && $complex->getReal() >= 0.0) {
return new Complex(\pow($complex->getReal(), $power));
}
$rValue = \sqrt(($complex->getReal() * $complex->getReal()) + ($complex->getImaginary() * $complex->getImaginary()));
$rPower = \pow($rValue, $power);
$theta = $complex->argument() * $power;
if ($theta == 0) {
return new Complex(1);
}
return new Complex($rPower * \cos($theta), $rPower * \sin($theta), $complex->getSuffix());
}

View File

@ -0,0 +1,28 @@
<?php
/**
*
* Function code for the complex rho() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the rho of a complex number.
* This is the distance/radius from the centrepoint to the representation of the number in polar coordinates.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The rho value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function rho($complex)
{
$complex = Complex::validateComplexArgument($complex);
return \sqrt(
($complex->getReal() * $complex->getReal()) +
($complex->getImaginary() * $complex->getImaginary())
);
}

View File

@ -0,0 +1,25 @@
<?php
/**
*
* Function code for the complex sec() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the secant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The secant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function sec($complex)
{
$complex = Complex::validateComplexArgument($complex);
return inverse(cos($complex));
}

View File

@ -0,0 +1,25 @@
<?php
/**
*
* Function code for the complex sech() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic secant of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic secant of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function sech($complex)
{
$complex = Complex::validateComplexArgument($complex);
return inverse(cosh($complex));
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex sin() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the sine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The sine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function sin($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\sin($complex->getReal()));
}
return new Complex(
\sin($complex->getReal()) * \cosh($complex->getImaginary()),
\cos($complex->getReal()) * \sinh($complex->getImaginary()),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,32 @@
<?php
/**
*
* Function code for the complex sinh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic sine of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic sine of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function sinh($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\sinh($complex->getReal()));
}
return new Complex(
\sinh($complex->getReal()) * \cos($complex->getImaginary()),
\cosh($complex->getReal()) * \sin($complex->getImaginary()),
$complex->getSuffix()
);
}

View File

@ -0,0 +1,29 @@
<?php
/**
*
* Function code for the complex sqrt() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the square root of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The Square root of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function sqrt($complex)
{
$complex = Complex::validateComplexArgument($complex);
$theta = theta($complex);
$delta1 = \cos($theta / 2);
$delta2 = \sin($theta / 2);
$rho = \sqrt(rho($complex));
return new Complex($delta1 * $rho, $delta2 * $rho, $complex->getSuffix());
}

View File

@ -0,0 +1,40 @@
<?php
/**
*
* Function code for the complex tan() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the tangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The tangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function tan($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->isReal()) {
return new Complex(\tan($complex->getReal()));
}
$real = $complex->getReal();
$imaginary = $complex->getImaginary();
$divisor = 1 + \pow(\tan($real), 2) * \pow(\tanh($imaginary), 2);
if ($divisor == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
return new Complex(
\pow(sech($imaginary)->getReal(), 2) * \tan($real) / $divisor,
\pow(sec($real)->getReal(), 2) * \tanh($imaginary) / $divisor,
$complex->getSuffix()
);
}

View File

@ -0,0 +1,35 @@
<?php
/**
*
* Function code for the complex tanh() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the hyperbolic tangent of a complex number.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return Complex The hyperbolic tangent of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
* @throws \InvalidArgumentException If function would result in a division by zero
*/
function tanh($complex)
{
$complex = Complex::validateComplexArgument($complex);
$real = $complex->getReal();
$imaginary = $complex->getImaginary();
$divisor = \cos($imaginary) * \cos($imaginary) + \sinh($real) * \sinh($real);
if ($divisor == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
return new Complex(
\sinh($real) * \cosh($real) / $divisor,
0.5 * \sin(2 * $imaginary) / $divisor,
$complex->getSuffix()
);
}

View File

@ -0,0 +1,38 @@
<?php
/**
*
* Function code for the complex theta() function
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Returns the theta of a complex number.
* This is the angle in radians from the real axis to the representation of the number in polar coordinates.
*
* @param Complex|mixed $complex Complex number or a numeric value.
* @return float The theta value of the complex argument.
* @throws Exception If argument isn't a valid real or complex number.
*/
function theta($complex)
{
$complex = Complex::validateComplexArgument($complex);
if ($complex->getReal() == 0.0) {
if ($complex->isReal()) {
return 0.0;
} elseif ($complex->getImaginary() < 0.0) {
return M_PI / -2;
}
return M_PI / 2;
} elseif ($complex->getReal() > 0.0) {
return \atan($complex->getImaginary() / $complex->getReal());
} elseif ($complex->getImaginary() < 0.0) {
return -(M_PI - \atan(\abs($complex->getImaginary()) / \abs($complex->getReal())));
}
return M_PI - \atan($complex->getImaginary() / \abs($complex->getReal()));
}

View File

@ -0,0 +1,46 @@
<?php
/**
*
* Function code for the complex addition operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Adds two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to add
* @return Complex
*/
function add(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
$real = $result->getReal() + $complex->getReal();
$imaginary = $result->getImaginary() + $complex->getImaginary();
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,56 @@
<?php
/**
*
* Function code for the complex division operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Divides two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to divide
* @return Complex
*/
function divideby(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
$delta1 = ($result->getReal() * $complex->getReal()) +
($result->getImaginary() * $complex->getImaginary());
$delta2 = ($result->getImaginary() * $complex->getReal()) -
($result->getReal() * $complex->getImaginary());
$delta3 = ($complex->getReal() * $complex->getReal()) +
($complex->getImaginary() * $complex->getImaginary());
$real = $delta1 / $delta3;
$imaginary = $delta2 / $delta3;
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,56 @@
<?php
/**
*
* Function code for the complex division operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Divides two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to divide
* @return Complex
*/
function divideinto(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
if ($result->getReal() == 0.0 && $result->getImaginary() == 0.0) {
throw new \InvalidArgumentException('Division by zero');
}
$delta1 = ($complex->getReal() * $result->getReal()) +
($complex->getImaginary() * $result->getImaginary());
$delta2 = ($complex->getImaginary() * $result->getReal()) -
($complex->getReal() * $result->getImaginary());
$delta3 = ($result->getReal() * $result->getReal()) +
($result->getImaginary() * $result->getImaginary());
$real = $delta1 / $delta3;
$imaginary = $delta2 / $delta3;
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,48 @@
<?php
/**
*
* Function code for the complex multiplication operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Multiplies two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to multiply
* @return Complex
*/
function multiply(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
$real = ($result->getReal() * $complex->getReal()) -
($result->getImaginary() * $complex->getImaginary());
$imaginary = ($result->getReal() * $complex->getImaginary()) +
($result->getImaginary() * $complex->getReal());
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,46 @@
<?php
/**
*
* Function code for the complex subtraction operation
*
* @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
* @license https://opensource.org/licenses/MIT MIT
*/
namespace Complex;
/**
* Subtracts two or more complex numbers
*
* @param array of string|integer|float|Complex $complexValues The numbers to subtract
* @return Complex
*/
function subtract(...$complexValues)
{
if (count($complexValues) < 2) {
throw new \Exception('This function requires at least 2 arguments');
}
$base = array_shift($complexValues);
$result = clone Complex::validateComplexArgument($base);
foreach ($complexValues as $complex) {
$complex = Complex::validateComplexArgument($complex);
if ($result->isComplex() && $complex->isComplex() &&
$result->getSuffix() !== $complex->getSuffix()) {
throw new Exception('Suffix Mismatch');
}
$real = $result->getReal() - $complex->getReal();
$imaginary = $result->getImaginary() - $complex->getImaginary();
$result = new Complex(
$real,
$imaginary,
($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
);
}
return $result;
}

View File

@ -0,0 +1,77 @@
{
"name": "markbaker/complex",
"type": "library",
"description": "PHP Class for working with complex numbers",
"keywords": ["complex", "mathematics"],
"homepage": "https://github.com/MarkBaker/PHPComplex",
"license": "MIT",
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"require": {
"php": "^5.6.0|^7.0.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.4.0",
"phpdocumentor/phpdocumentor":"2.*",
"phpmd/phpmd": "2.*",
"sebastian/phpcpd": "2.*",
"phploc/phploc": "2.*",
"squizlabs/php_codesniffer": "^3.3.0",
"phpcompatibility/php-compatibility": "^8.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3"
},
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
},
"files": [
"classes/src/functions/abs.php",
"classes/src/functions/acos.php",
"classes/src/functions/acosh.php",
"classes/src/functions/acot.php",
"classes/src/functions/acoth.php",
"classes/src/functions/acsc.php",
"classes/src/functions/acsch.php",
"classes/src/functions/argument.php",
"classes/src/functions/asec.php",
"classes/src/functions/asech.php",
"classes/src/functions/asin.php",
"classes/src/functions/asinh.php",
"classes/src/functions/atan.php",
"classes/src/functions/atanh.php",
"classes/src/functions/conjugate.php",
"classes/src/functions/cos.php",
"classes/src/functions/cosh.php",
"classes/src/functions/cot.php",
"classes/src/functions/coth.php",
"classes/src/functions/csc.php",
"classes/src/functions/csch.php",
"classes/src/functions/exp.php",
"classes/src/functions/inverse.php",
"classes/src/functions/ln.php",
"classes/src/functions/log2.php",
"classes/src/functions/log10.php",
"classes/src/functions/negative.php",
"classes/src/functions/pow.php",
"classes/src/functions/rho.php",
"classes/src/functions/sec.php",
"classes/src/functions/sech.php",
"classes/src/functions/sin.php",
"classes/src/functions/sinh.php",
"classes/src/functions/sqrt.php",
"classes/src/functions/tan.php",
"classes/src/functions/tanh.php",
"classes/src/functions/theta.php",
"classes/src/operations/add.php",
"classes/src/operations/subtract.php",
"classes/src/operations/multiply.php",
"classes/src/operations/divideby.php",
"classes/src/operations/divideinto.php"
]
},
"minimum-stability": "dev"
}

View File

@ -0,0 +1,154 @@
<?php
use Complex\Complex as Complex;
include('../classes/Bootstrap.php');
echo 'Create', PHP_EOL;
$x = new Complex(123);
echo $x, PHP_EOL;
$x = new Complex(123, 456);
echo $x, PHP_EOL;
$x = new Complex(array(123,456,'j'));
echo $x, PHP_EOL;
$x = new Complex('1.23e-4--2.34e-5i');
echo $x, PHP_EOL;
echo PHP_EOL, 'Add', PHP_EOL;
$x = new Complex(123);
$x->add(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->add(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->add(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->add(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->add(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->add(new Complex(0, -1));
echo $x, PHP_EOL;
echo PHP_EOL, 'Subtract', PHP_EOL;
$x = new Complex(123);
$x->subtract(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->subtract(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->subtract(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->subtract(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->subtract(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->subtract(new Complex(0, -1));
echo $x, PHP_EOL;
echo PHP_EOL, 'Multiply', PHP_EOL;
$x = new Complex(123);
$x->multiply(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->multiply(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->multiply(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->multiply(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->multiply(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->multiply(new Complex(0, -1));
echo $x, PHP_EOL;
echo PHP_EOL, 'Divide By', PHP_EOL;
$x = new Complex(123);
$x->divideBy(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->divideBy(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->divideBy(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->divideBy(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->divideBy(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->divideBy(new Complex(0, -1));
echo $x, PHP_EOL;
echo PHP_EOL, 'Divide Into', PHP_EOL;
$x = new Complex(123);
$x->divideInto(456);
echo $x, PHP_EOL;
$x = new Complex(123.456);
$x->divideInto(789.012);
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->divideInto(new Complex(-987.654, -32.1));
echo $x, PHP_EOL;
$x = new Complex(123.456, 78.90);
$x->divideInto(-987.654);
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->divideInto(new Complex(0, 1));
echo $x, PHP_EOL;
$x = new Complex(-987.654, -32.1);
$x->divideInto(new Complex(0, -1));
echo $x, PHP_EOL;

View File

@ -0,0 +1,52 @@
<?php
namespace Complex;
include('../classes/Bootstrap.php');
echo 'Function Examples', PHP_EOL;
$functions = array(
'abs',
'acos',
'acosh',
'acsc',
'acsch',
'argument',
'asec',
'asech',
'asin',
'asinh',
'conjugate',
'cos',
'cosh',
'csc',
'csch',
'exp',
'inverse',
'ln',
'log2',
'log10',
'rho',
'sec',
'sech',
'sin',
'sinh',
'sqrt',
'theta'
);
for ($real = -3.5; $real <= 3.5; $real += 0.5) {
for ($imaginary = -3.5; $imaginary <= 3.5; $imaginary += 0.5) {
foreach ($functions as $function) {
$complexFunction = __NAMESPACE__ . '\\' . $function;
$complex = new Complex($real, $imaginary);
try {
echo $function, '(', $complex, ') = ', $complexFunction($complex), PHP_EOL;
} catch (\Exception $e) {
echo $function, '(', $complex, ') ERROR: ', $e->getMessage(), PHP_EOL;
}
}
echo PHP_EOL;
}
}

View File

@ -0,0 +1,34 @@
<?php
use Complex\Complex as Complex;
include('../classes/Bootstrap.php');
$values = [
new Complex(123),
new Complex(456, 123),
new Complex(0.0, 456),
];
foreach ($values as $value) {
echo $value, PHP_EOL;
}
echo 'Addition', PHP_EOL;
$result = \Complex\add(...$values);
echo '=> ', $result, PHP_EOL;
echo PHP_EOL;
echo 'Subtraction', PHP_EOL;
$result = \Complex\subtract(...$values);
echo '=> ', $result, PHP_EOL;
echo PHP_EOL;
echo 'Multiplication', PHP_EOL;
$result = \Complex\multiply(...$values);
echo '=> ', $result, PHP_EOL;

25
inc/vendor/markbaker/complex/license.md vendored Normal file
View File

@ -0,0 +1,25 @@
The MIT License (MIT)
=====================
Copyright © `2017` `Mark Baker`
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.

5
inc/vendor/pacificsec/cpe/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/.settings/
/.buildpath
/.project
/vendor/
/composer.lock

View File

@ -22,3 +22,45 @@ Features
- CPE rich comparison.
- CPE Language parsing and evaluation.
- MIT Licensed.
Getting Started
--------
- Clone repository
```bash
$ git clone https://github.com/pacificsec/cpe.git
$ cd cpe
```
- Create a new PHP file to run tests
```php
<?php
require('autoload.php');
use PacificSec\CPE\Matching\CPENameMatcher;
use PacificSec\CPE\Naming\CPENameUnbinder;
use PacificSec\CPE\Naming\CPENameBinder;
CPENameMatcher::test();
CPENameUnbinder::test();
CPENameBinder::test();
```
```php
<?php
require('autoload.php');
use PacificSec\CPE\Naming\CPENameUnbinder;
$cpenu = new CPENameUnbinder();
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer%01%01%01%01:?:beta");
var_dump($wfn);
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer:8.%2a:sp%3f");
var_dump($wfn);
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer:8.%02:sp%01");
var_dump($wfn);
$wfn = $cpenu->unbindURI("cpe:/a:hp:insight_diagnostics:7.4.0.1570::~~online~win2003~x64~");
var_dump($wfn);
$wfn = $cpenu->unbindFS("cpe:2.3:a:micr\\?osoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*");
var_dump($wfn);
```

26
inc/vendor/pacificsec/cpe/composer.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"name" : "pacificsec/cpe",
"type" : "library",
"description" : "CPE: Common Platform Enumeration for PHP",
"keywords" : [
"cpe",
"cve",
"security",
"pacificsec"
],
"homepage" : "https://github.com/pacificsec/cpe",
"license" : "MIT",
"authors" : [{
"name" : "Antonio Franco",
"email" : "antonio.franco@pacificsec.com"
}
],
"require" : {
"php" : ">=5.3.0"
},
"autoload" : {
"psr-4" : {
"PacificSec\\CPE\\" : "src"
}
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace PacificSec\CPE\Common;
use \Exception;
/**
* This class represents a Logical Value. It is based on Java version
* implemented by JKRAUNELIS <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class LogicalValue {
private $any = false;
private $na = false;
// Object must be constructed with the string "ANY" or "NA".
public function __construct($type) {
if ($type == "ANY") {
$this->any = true;
} else if ($type == "NA") {
$this->na = true;
} else {
throw new Exception("LogicalValue must be ANY or NA");
}
}
public function isANY(){
return $this->any;
}
public function isNA(){
return $this->na;
}
public function __toString(){
if ($this->any){
return "ANY";
}
return "NA";
}
}

View File

@ -0,0 +1,166 @@
<?php
namespace PacificSec\CPE\Common;
use \Exception;
/**
* A collection of utility functions for use with the matching and
* naming namespaces. It is based on Java version implemented by
* Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class Utilities {
/**
* Searches string for special characters * and ?
* @param string $string to be searched
* @return bool true if string contains wildcard, false otherwise
*/
public static function containsWildcards($string) {
if (strpos($string, "*") !== false || strpos($string, "?") !== false) {
if (!(strpos($string, "\\") !== false)) {
return true;
}
}
return false;
}
/**
* Checks if given number is even or not
* @param int $num number to check
* @return bool true if number is even, false if not
*/
public static function isEvenNumber($num) {
return (is_int($num) && $num % 2 == 0);
}
/**
* Counts the number of escape characters in the string beginning and ending
* at the given indices
* @param string $str string to search
* @param int $start beginning index
* @param int $end ending index
* @return number of escape characters in string
* @todo fix the use of $str. The Java version is also not using this variable.
*/
public static function countEscapeCharacters($str, $start, $end) {
$result = 0;
$active = false;
$i = 0;
while ($i < $end) {
if ($active && ($i >= $start)) {
$result = $result + 1;
}
$i = $i + 1;
}
return $result;
}
/**
* Searches a string for the first unescaped colon and returns the index of
* that colon
* @param string $str string to search
* @return int index of first unescaped colon, or 0 if not found
*/
public static function getUnescapedColonIndex($str) {
$found = false;
$colon_idx = 0;
$start_idx = 0;
// Find the first non-escaped colon.
while (!$found) {
$colon_idx = strpos($str, ":", $start_idx + 1);
// If no colon is found, return 0.
if ($colon_idx === false) {
return 0;
}
// Peek at character before colon.
if (substr($str, $colon_idx-1, 1) == "\\") {
// If colon is escaped, keep looking.
$start_idx = $colon_idx;
} else {
$found = true;
}
}
return $colon_idx;
}
/**
* Returns true if the string contains only
* alphanumeric characters or the underscore character,
* false otherwise.
* @param string $c the string in question
* @return bool true if $c is alphanumeric or underscore, false if not
*/
public static function isAlphanum($c) {
return (preg_match("/^[a-zA-Z0-9\_]+$/", $c) ? true : false);
}
/**
* This function is not part of the reference implementation pseudo code
* found in the CPE 2.3 specification. It enforces two rules in the
* specification:
* URI must start with the characters "cpe:/"
* A URI may not contain more than 7 components
* If either rule is violated, a Exception is thrown.
* @param $in string with URI to be validated
*/
public static function validateURI($in) {
// make sure uri starts with cpe:/
if (strpos(strtolower($in), "cpe:/") !== 0) {
throw new Exception("Error: URI must start with 'cpe:/'. Given: " . $in, 0);
}
// make sure uri doesn't contain more than 7 colons
$count = sizeof(explode(":", $in));
if ($count > 8) {
throw new Exception("Error parsing URI. Found " . ($count - 8) . " extra components in: " . $in, 0);
}
}
/**
* This function is not part of the reference implementation pseudo code
* found in the CPE 2.3 specification. It enforces three rules found in the
* specification:
* Formatted string must start with the characters "cpe:2.3:"
* A formatted string must contain 11 components
* A formatted string must not contain empty components
* If any rule is violated, a ParseException is thrown.
* @param $in string with FS to be validated
*/
public static function validateFS($in) {
if (strpos(strtolower($in), "cpe:2.3:") !== 0) {
throw new Exception("Error: Formatted String must start with \"cpe:2.3\". Given: " . $in, 0);
}
$count = 0;
for ($i = 0; $i != strlen($in); $i++){
if (substr($in, $i, 1) == ":"){
if (substr($in, $i - 1, 1) != "\\"){
$count++;
}
if (($i+1) < strlen($in) && substr($in, $i+1, 1) == ":"){
throw new Exception("Error parsing formatted string. Found empty component", 0);
}
}
}
if ($count > 12){
$extra = $count - 12;
$s = "Error parsing formatted string. Found " . $extra . " extra component";
if ($extra > 1){
$s = $s . "s";
}
$s = $s . " in: " . $in;
throw new Exception($s, 0);
}
if ($count < 12){
$missing = 12 - $count;
$s = "Error parsing formatted string. Missing " . $missing . " component";
if ($missing > 1){
$s = $s . "s";
}
throw new Exception($s, 0);
}
}
}

View File

@ -0,0 +1,210 @@
<?php
namespace PacificSec\CPE\Common;
use \Exception;
/**
* The WellFormedName class represents a Well Formed Name, as defined
* in the CPE Specification version 2.3. It is based on Java version
* implemented by jkraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for details.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class WellFormedName {
// Underlying wfn representation.
private $wfn = null;
// All permissible WFN attributes as defined by specification.
private $attributes = array("part", "vendor", "product", "version",
"update", "edition", "language", "sw_edition", "target_sw",
"target_hw", "other");
/**
* Constructs a new WellFormedName object, setting each component to the
* given parameter value. If a parameter is null, the component is set to
* the default value "ANY".
* @param $part string representing the part component
* @param $vendor string representing the vendor component
* @param $product string representing the product component
* @param $version string representing the version component
* @param $update string representing the update component
* @param $edition string representing the edition component
* @param $language string representing the language component
* @param $sw_edition string representing the sw_edition component
* @param $target_sw string representing the target_sw component
* @param $target_hw string representing the target_hw component
* @param $other string representing the other component
*/
public function __construct($part = null, $vendor = null, $product = null, $version = null,
$update = null, $edition = null, $language = null, $sw_edition = null, $target_sw = null,
$target_hw = null, $other = null) {
$this->wfn = array();
// Constructs a new WellFormedName object, with all components set to the default value "ANY".
if ($part === null && $vendor === null && $product === null && $version === null &&
$update === null && $edition === null && $language === null && $sw_edition === null && $target_sw === null &&
$target_hw === null && $other === null){
foreach ($this->attributes as $a){
if ($a != "part"){
$this->set($a, new LogicalValue("ANY"));
}
}
return;
}
$this->set("part", $part);
$this->set("vendor", $vendor);
$this->set("product", $product);
$this->set("version", $version);
$this->set("update", $update);
$this->set("edition", $edition);
$this->set("language", $language);
$this->set("sw_edition", $sw_edition);
$this->set("target_sw", $target_sw);
$this->set("target_hw", $target_hw);
$this->set("other", $other);
}
/**
* @param $attribute string representing the component value to get
* @return string the string value of the given component, or default value "ANY"
* if the component does not exist
*/
public function get($attribute){
if (array_key_exists($attribute, $this->wfn))
return $this->wfn[$attribute];
else
return new LogicalValue("ANY");
}
/**
* Sets the given attribute to value, if the attribute is in the list of
* permissible components
* @param $attribute string representing the component to set
* @param $value object or string representing the value of the given component
*/
public final function set($attribute, $value){
// Iterate over permissible attributes.
foreach ($this->attributes as $a){
// If the argument is a valid attribute, set that attribute's value.
if ($attribute == $a) {
// check to see if we're setting a LogicalValue ANY or NA
if ($value instanceof LogicalValue){
// don't allow logical values in part component
if ($attribute == "part"){
var_dump($value); echo "<br>\n";
var_dump($a); echo "<br>\n";
var_dump($attribute); echo "<br>\n";
throw new Exception("Error! part component cannot be a logical value");
}
// put the Object in the ht and break
$this->wfn[$attribute] = $value;
break;
}
if ($value == null || $value == ""){
// if value is null or blank, set attribute to default logical ANY
$this->wfn[$attribute] = new LogicalValue("ANY");
break;
}
$svalue = $value;
// Reg exs
// check for printable characters - no control characters
if (!preg_match("/^[[:print:]]*$/", $svalue)){
throw new Exception("Error! encountered non printable character in: " . $svalue, 0);
}
// svalue has whitespace
if (preg_match("/^.*\\s+.*$/", $svalue)){
throw new Exception("Error! component cannot contain whitespace: " . $svalue, 0);
}
// svalue has more than one unquoted star
if (preg_match("/^\\*{2,}.*$/", $svalue) || preg_match("/^.*\\*{2,}$/", $svalue)){
throw new Exception("Error! component cannot contain more than one * in sequence: " . $svalue, 0);
}
// svalue has unquoted punctuation embedded
if (preg_match("/^.*(?<!\\\\)[\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\+\\,\\.\\/\\:\\;\\<\\=\\>\\@\\[\\]\\^\\`\\{\\|\\}\\~\\-].*$/", $svalue)) {
throw new Exception("Error! component cannot contain unquoted punctuation: " . $svalue, 0);
}
// svalue has an unquoted *
if (preg_match("/^.+(?<!\\\\)[\\*].+$/", $svalue)) {
throw new Exception("Error! component cannot contain embedded *: " . $svalue, 0);
}
// svalue has embedded unquoted ?
// this will catch a single unquoted ?, so make sure we deal with that
if (strpos($svalue, "?") !== false) {
if ($svalue == "?") {
// single ? is valid
$this->wfn[$attribute] = $svalue;
break;
}
// remove leading and trailing ?s
$v = $svalue;
while (strpos($v, "?") === 0) {
// remove all leading ?'s
$v = substr($v, 1);
}
$v = strrev($v);
while (strpos($v, "?") === 0) {
// remove all trailing ?'s (string has been reversed)
$v = substr($v, 1);
}
// back to normal
$v = strrev($v);
// after leading and trailing ?s are removed, check if value
// contains unquoted ?s
if (preg_match("/^.+(?<!\\\\)[\\?].+$/", $v)) {
throw new Exception("Error! component cannot contain embedded ?: " . $svalue, 0);
}
}
// single asterisk is not allowed
if ($svalue == "*") {
throw new Exception("Error! component cannot be a single *: " . $svalue, 0);
}
// quoted hyphen not allowed by itself
if ($svalue == "-") {
throw new Exception("Error! component cannot be quoted hyphen: " . $svalue, 0);
}
// part must be a, o, or h
if ($attribute == "part") {
if ($svalue != "a" && $svalue != "o" && $svalue != "h") {
throw new Exception("Error! part component must be one of the following: 'a', 'o', 'h': " . $svalue, 0);
}
}
// should be good to go
$this->wfn[$attribute] = $svalue;
break;
}
}
}
/**
*
* @return string representation of the WellFormedName
*/
public function __toString() {
$str = "wfn:[";
foreach ($this->attributes as $attr) {
$str = $str . $attr;
$str = $str . "=";
$o = $this->wfn[$attr];
if ($o instanceof LogicalValue) {
$str = $str . $o;
$str = $str . ", ";
} else {
$str = $str . "\"";
$str = $str . $o;
$str = $str . "\", ";
}
}
$str = substr($str, 0, strlen($str)-1);
$str = substr($str, 0, strlen($str)-1);
$str = $str . "]";
return $str;
}
}

View File

@ -0,0 +1,287 @@
<?php
namespace PacificSec\CPE\Matching;
use PacificSec\CPE\Common\WellFormedName;
use PacificSec\CPE\Common\Utilities;
use PacificSec\CPE\Common\LogicalValue;
use PacificSec\CPE\Naming\CPENameBinder;
use PacificSec\CPE\Naming\CPENameUnbinder;
/**
* The CPENameMatcher is an implementation of the CPE Matching algorithm,
* as specified in the CPE Matching Standard version 2.3. It is based on
* Java version implemented by Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class CPENameMatcher {
/**
* Tests two Well Formed Names for disjointness.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the names are disjoint, false otherwise
*/
public function isDisjoint(WellFormedName $source, WellFormedName $target) {
// if any pairwise comparison is disjoint, the names are disjoint.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result == Relation::DISJOINT)
return true;
}
return false;
}
/**
* Tests two Well Formed Names for equality.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the names are equal, false otherwise
*/
public function isEqual(WellFormedName $source, WellFormedName $target) {
// if every pairwise comparison is equal, the names are equal.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::EQUAL){
return false;
}
}
return true;
}
/**
* Tests if the target Well Formed Name is a subset of the source Well Formed
* Name.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the target is a subset of the source, false otherwise
*/
public function isSubset(WellFormedName $source, WellFormedName $target) {
// if any comparison is anything other than subset or equal, then target is
// not a subset of source.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::SUBSET && $result != Relation::EQUAL) {
return false;
}
}
return true;
}
/**
* Tests if the target Well Formed name is a superset of the source Well Formed
* Name.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the target is a superset of the source, false otherwise
*/
public function isSuperset(WellFormedName $source, WellFormedName $target) {
// if any comparison is anything other than superset or equal, then target is not
// a superset of source.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::SUPERSET && $result != Relation::EQUAL) {
return false;
}
}
return true;
}
/**
* Compares each attribute value pair in two Well Formed Names.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return array A array mapping attribute string to attribute value Relation
*/
public function compareWFNs(WellFormedName $source, WellFormedName $target) {
$result = array();
$result["part"] = $this->compare($source->get("part"), $target->get("part"));
$result["vendor"] = $this->compare($source->get("vendor"), $target->get("vendor"));
$result["product"] = $this->compare($source->get("product"), $target->get("product"));
$result["version"] = $this->compare($source->get("version"), $target->get("version"));
$result["update"] = $this->compare($source->get("update"), $target->get("update"));
$result["edition"] = $this->compare($source->get("edition"), $target->get("edition"));
$result["language"] = $this->compare($source->get("language"), $target->get("language"));
$result["sw_edition"] = $this->compare($source->get("sw_edition"), $target->get("sw_edition"));
$result["target_sw"] = $this->compare($source->get("target_sw"), $target->get("target_sw"));
$result["target_hw"] = $this->compare($source->get("target_hw"), $target->get("target_hw"));
$result["other"] = $this->compare($source->get("other"), $target->get("other"));
return $result;
}
/**
* Compares an attribute value pair.
* @param string $source Source attribute value.
* @param string $target Target attribute value.
* @return int The relation between the two attribute values.
*/
private function compare($source, $target) {
// matching is case insensitive, convert strings to lowercase.
if ($this->isString($source)) {
$source = strtolower($source);
}
if ($this->isString($target)) {
$target = strtolower($target);
}
// Unquoted wildcard characters yield an undefined result.
if ($this->isString($target) && Utilities::containsWildcards($target)) {
return Relation::UNDEFINED;
}
// If source and target values are equal, then result is equal.
if ($source == $target) {
return Relation::EQUAL;
}
// Check to see if source or target are Logical Values.
$lvSource = null;
$lvTarget = null;
if ($source instanceof LogicalValue) {
$lvSource = $source;
}
if ($target instanceof LogicalValue) {
$lvTarget = $target;
}
if ($lvSource != null && $lvTarget != null) {
// If Logical Values are equal, result is equal.
if ($lvSource->isANY() == $lvTarget->isANY() || $lvSource->isNA() == $lvTarget->isNA()) {
return Relation::EQUAL;
}
}
// If source value is ANY, result is a superset.
if ($lvSource != null) {
if ($lvSource->isANY()) {
return Relation::SUPERSET;
}
}
// If target value is ANY, result is a subset.
if ($lvTarget != null) {
if ($lvTarget->isANY()) {
return Relation::SUBSET;
}
}
// If source or target is NA, result is disjoint.
if ($lvSource != null) {
if ($lvSource->isNA()) {
return Relation::DISJOINT;
}
}
if ($lvTarget != null) {
if ($lvTarget->isNA()) {
return Relation::DISJOINT;
}
}
// only Strings will get to this point, not LogicalValues
return $this->compareStrings($source, $target);
}
/**
* Compares a source string to a target string, and addresses the condition
* in which the source string includes unquoted special characters. It
* performs a simple regular expression match, with the assumption that
* (as required) unquoted special characters appear only at the beginning
* and/or the end of the source string. It also properly differentiates
* between unquoted and quoted special characters.
*
* @param $source string Source attribute value.
* @param $target string Target attribute value.
* @return Relation between source and target Strings.
*/
private function compareStrings($source, $target) {
$start = 0;
$end = strlen($source);
$begins = 0;
$ends = 0;
$index = 0; $leftover = 0; $escapes = 0;
if (substr($source, 0, 1) == "*") {
$start = 1;
$begins = -1;
} else {
while (($start < strlen($source)) && (substr($source, $start, 1) == "?")) {
$start = $start + 1;
$begins = $begins + 1;
}
}
if ((substr($source, $end - 1, 1) == "*") && ($this->isEvenWildcards($source, $end - 1))) { //TODO
$end = $end - 1;
$ends = -1;
} else {
while (($end > 0) && substr($source, $end - 1, 1) == "?" && ($this->isEvenWildcards($source, $end - 1))) { //TODO
$end = $end - 1;
$ends = $ends + 1;
}
}
$source = substr($source, $start, $end-$start);
$index = -1;
$leftover = strlen($target);
while ($leftover > 0) {
$index = strpos($target, $source, $index + 1);
if ($index === false) {
break;
}
$escapes = Utilities::countEscapeCharacters($target, 0, $index);
if (($index > 0) && ($begins != -1) && ($begins < ($index - $escapes))) {
break;
}
$escapes = Utilities::countEscapeCharacters($target, $index + 1, strlen($target));
$leftover = strlen($target) - $index - $escapes - strlen($source);
if (($leftover > 0) && (($ends != -1) && ($leftover > $ends))) {
continue;
}
return Relation::SUPERSET;
}
return Relation::DISJOINT;
}
/**
* Searches a string for the backslash character
* @param $str string to search in
* @param int $idx end index
* @return true if the number of backslash characters is even, false if odd
*/
private function isEvenWildcards($str, $idx) {
$result = 0;
while (($idx > 0) && (strpos($str, "\\", $idx - 1)) !== false) {
$idx = $idx - 1;
$result = $result + 1;
}
return Utilities::isEvenNumber($result);
}
/**
* Tests if an Object is an instance of the String class
* @param mixed $arg the var to test
* @return bool true if arg is a string, false if not
*/
private function isString($arg) {
return is_string($arg);
}
/*
* Static method to demonstrate this class.
*/
public static function test() {
// Examples.
$wfn = new WellFormedName("a", "microsoft", "internet_explorer", "8\\.0\\.6001", "beta", new LogicalValue("ANY"), "sp2", null, null, null, null);
$wfn2 = new WellFormedName("a", "microsoft", "internet_explorer", new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"));
$cpenm = new CPENameMatcher();
$cpenu = new CPENameUnbinder();
$cpenb = new CPENameBinder();
$wfn = $cpenu->unbindURI($cpenb->bindToURI($wfn));
$wfn2 = $cpenu->unbindFS($cpenb->bindToFS($wfn2));
var_dump($cpenm->isDisjoint($wfn, $wfn2)); // false
var_dump($cpenm->isEqual($wfn, $wfn2)); // false
var_dump($cpenm->isSubset($wfn, $wfn2)); // true, $wfn2 is a subset of wfn
var_dump($cpenm->isSuperset($wfn, $wfn2)); // false
$wfn = $cpenu->unbindFS("cpe:2.3:a:adobe:*:9.*:*:PalmOS:*:*:*:*:*");
$wfn2 = $cpenu->unbindURI("cpe:/a::Reader:9.3.2:-:-");
var_dump($cpenm->isDisjoint($wfn, $wfn2)); // true, $wfn2 and wfn are disjoint
var_dump($cpenm->isEqual($wfn, $wfn2)); // false
var_dump($cpenm->isSubset($wfn, $wfn2)); // false
var_dump($cpenm->isSuperset($wfn, $wfn2)); // false
}
}

View File

@ -7,28 +7,41 @@ use PacificSec\CPE\Common\LogicalValue;
/**
* The CPENameBinder class is a simple implementation
* of the CPE Name binding algorithm, as specified in the
* CPE Naming Standard version 2.3. It is based on Java version
* implemented by Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* of the CPE Name binding algorithm, as specified in the
* CPE Naming Standard version 2.3.
* It is based on Java version
* implemented by Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class CPENameBinder {
class CPENameBinder
{
/**
* Binds a {@link WellFormedName} object to a URI.
* @param $w WellFormedName to be bound to URI
* @return URI binding of WFN
*
* @param $w WellFormedName
* to be bound to URI
* @return string URI binding of WFN
*/
public function bindToURI(WellFormedName $w) {
public function bindToURI(WellFormedName $w)
{
// Initialize the output with the CPE v2.2 URI prefix.
$uri = "cpe:/";
// Define the attributes that correspond to the seven components in a v2.2. CPE.
$attributes = array("part", "vendor", "product", "version", "update", "edition", "language");
$attributes = array(
"part",
"vendor",
"product",
"version",
"update",
"edition",
"language"
);
// Iterate over the well formed name
foreach ($attributes as $a) {
@ -56,15 +69,28 @@ class CPENameBinder {
/**
* Top-level function used to bind WFN w to formatted string.
* @param $w WellFormedName to bind
* @return Formatted String
*
* @param $w WellFormedName
* to bind
* @return string Formatted String
*/
public function bindToFS(WellFormedName $w) {
public function bindToFS(WellFormedName $w)
{
// Initialize the output with the CPE v2.3 string prefix.
$fs = "cpe:2.3:";
foreach (array("part", "vendor", "product", "version",
"update", "edition", "language", "sw_edition", "target_sw",
"target_hw", "other") as $a) {
foreach (array(
"part",
"vendor",
"product",
"version",
"update",
"edition",
"language",
"sw_edition",
"target_sw",
"target_hw",
"other"
) as $a) {
$v = $this->bindValueForFS($w->get($a));
$fs = $fs . $v;
// add a colon except at the very end
@ -78,10 +104,13 @@ class CPENameBinder {
/**
* Convert the value v to its proper string representation for insertion to
* formatted string.
* @param $v value to convert
* @return Formatted value
*
* @param mixed $v
* value to convert
* @return mixed Formatted value
*/
private function bindValueForFS($v) {
private function bindValueForFS($v)
{
if ($v instanceof LogicalValue) {
$l = $v;
// The value NA binds to a blank.
@ -97,30 +126,34 @@ class CPENameBinder {
}
/**
* Inspect each character in string s. Certain nonalpha characters pass
* Inspect each character in string s.
* Certain nonalpha characters pass
* thru without escaping into the result, but most retain escaping.
* @param $s
* @return
*
* @param
* $s
* @return
*/
private function processQuotedChars($s) {
private function processQuotedChars($s)
{
$result = "";
$idx = 0;
while ($idx < strlen($s)) {
$c = substr($s, $idx, 1);
if ($c != "\\") {
// unquoted characters pass thru unharmed.
$result = $result . $c;
$result .= $c;
} else {
// escaped characters are examined.
$nextchr = substr($s, $idx + 1, 1);
// the period, hyphen and underscore pass unharmed.
if ($nextchr == "." || $nextchr == "-" || $nextchr == "_") {
$result = $result . $nextchr;
$result .= $nextchr;
$idx = $idx + 2;
continue;
} else {
// all others retain escaping.
$result = $result . "\\" . $nextchr;
$result .= "\\" . $nextchr;
$idx = $idx + 2;
continue;
}
@ -132,12 +165,16 @@ class CPENameBinder {
/**
* Converts a string to the proper string for including in
* a CPE v2.2-conformant URI. The logical value ANY binds
* a CPE v2.2-conformant URI.
* The logical value ANY binds
* to the blank in the 2.2-conformant URI.
* @param $s string to be converted
* @return converted string
*
* @param $s string
* to be converted
* @return string converted string
*/
private function bindValueForURI($s) {
private function bindValueForURI($s)
{
if ($s instanceof LogicalValue) {
$l = $s;
// The value NA binds to a blank.
@ -159,10 +196,13 @@ class CPENameBinder {
* - Pass alphanumeric characters thru untouched
* - Percent-encode quoted non-alphanumerics as needed
* - Unquoted special characters are mapped to their special forms
* @param $s string to be transformed
* @return transformed string
*
* @param $s string
* to be transformed
* @return string transformed string
*/
private function transformForURI($s) {
private function transformForURI($s)
{
$result = "";
$idx = 0;
@ -171,7 +211,7 @@ class CPENameBinder {
$thischar = substr($s, $idx, 1);
// Alphanumerics (incl. underscore) pass untouched.
if (Utilities::isAlphanum($thischar)) {
$result = $result . $thischar;
$result .= $thischar;
$idx = $idx + 1;
continue;
}
@ -179,17 +219,17 @@ class CPENameBinder {
if ($thischar == "\\") {
$idx = $idx + 1;
$nxtchar = substr($s, $idx, 1);
$result = $result . $this->pctEncode($nxtchar);
$result .= $this->pctEncode($nxtchar);
$idx = $idx + 1;
continue;
}
// Bind the unquoted '?' special character to "%01".
if ($thischar == "?") {
$result = $result . "%01";
$result .= "%01";
}
// Bind the unquoted '*' special character to "%02".
if ($thischar == "*") {
$result = $result . "%02";
$result .= "%02";
}
$idx = $idx + 1;
}
@ -199,122 +239,98 @@ class CPENameBinder {
/**
* Returns the appropriate percent-encoding of character c.
* Certain characters are returned without encoding.
* @param $c the single character string to be encoded
* @return the percent encoded string
*
* @param string $c the
* single character string to be encoded
* @return string the percent encoded string
*/
private function pctEncode($c) {
if ($c == "!") {
return "%21";
private function pctEncode($c)
{
switch ($c) {
case '!':
return "%21";
case "\"":
return "%22";
case "#":
return "%23";
case "$":
return "%24";
case "%":
return "%25";
case "&":
return "%26";
case "'":
return "%27";
case "(":
return "%28";
case ")":
return "%29";
case "*":
return "%2a";
case "+":
return "%2b";
case ",":
return "%2c";
case "/":
return "%2f";
case ":":
return "%3a";
case ";":
return "%3b";
case "<":
return "%3c";
case "=":
return "%3d";
case ">":
return "%3e";
case "?":
return "%3f";
case "@":
return "%40";
case "[":
return "%5b";
case "\\":
return "%5c";
case "]":
return "%5d";
case "^":
return "%5e";
case "`":
return "%60";
case "{":
return "%7b";
case "|":
return "%7c";
case "}":
return "%7d";
case "~":
return "%7e";
default:
return $c;
}
if ($c == "\"") {
return "%22";
}
if ($c == "#") {
return "%23";
}
if ($c == "$") {
return "%24";
}
if ($c == "%") {
return "%25";
}
if ($c == "&") {
return "%26";
}
if ($c == "'") {
return "%27";
}
if ($c == "(") {
return "%28";
}
if ($c == ")") {
return "%29";
}
if ($c == "*") {
return "%2a";
}
if ($c == "+") {
return "%2b";
}
if ($c == ",") {
return "%2c";
}
// bound without encoding.
if ($c == "-") {
return $c;
}
// bound without encoding.
if ($c == ".") {
return $c;
}
if ($c == "/") {
return "%2f";
}
if ($c == ":") {
return "%3a";
}
if ($c == ";") {
return "%3b";
}
if ($c == "<") {
return "%3c";
}
if ($c == "=") {
return "%3d";
}
if ($c == ">") {
return "%3e";
}
if ($c == "?") {
return "%3f";
}
if ($c == "@") {
return "%40";
}
if ($c == "[") {
return "%5b";
}
if ($c == "\\") {
return "%5c";
}
if ($c == "]") {
return "%5d";
}
if ($c == "^") {
return "%5e";
}
if ($c == "`") {
return "%60";
}
if ($c == "{") {
return "%7b";
}
if ($c == "|") {
return "%7c";
}
if ($c == "}") {
return "%7d";
}
if ($c == "~") {
return "%7d";
}
// Shouldn't reach here, return original character
return $c;
}
/**
* Packs the values of the five arguments into the single
* edition component. If all the values are blank, the
* Packs the values of the five arguments into the single
* edition component.
* If all the values are blank, the
* function returns a blank.
* @param $ed edition string
* @param $sw_ed software edition string
* @param $t_sw target software string
* @param $t_hw target hardware string
* @param $oth other edition information string
* @return the packed string, or blank
*
* @param string $ed edition
* string
* @param string $sw_ed software
* edition string
* @param string $t_sw target
* software string
* @param string $t_hw target
* hardware string
* @param string $oth other
* edition information string
* @return string the packed string, or blank
*/
private function pack($ed, $sw_ed, $t_sw, $t_hw, $oth) {
if ($sw_ed == "" && $t_sw == "" && $t_hw == "" && $oth == "") {
private function pack($ed, $sw_ed, $t_sw, $t_hw, $oth)
{
if ($sw_ed == "" && $t_sw == "" && $t_hw == "" && $oth == "") {
// All the extended attributes are blank, so don't do
// any packing, just return ed.
return $ed;
@ -326,13 +342,16 @@ class CPENameBinder {
/**
* Removes trailing colons from the URI.
* @param $s the string to be trimmed
* @return the trimmed string
*
* @param string $s the
* string to be trimmed
* @return string the trimmed string
*/
private function trim($s) {
private function trim($s)
{
$s1 = strrev($s);
$idx = 0;
for ($i = 0; $i != strlen($s1); $i++) {
for ($i = 0; $i != strlen($s1); $i ++) {
if (substr($s1, $i, 1) == ":") {
$idx = $idx + 1;
} else {
@ -341,30 +360,30 @@ class CPENameBinder {
}
// Return the substring after all trailing colons,
// reversed back to its original character order.
return strrev(substr($s1, $idx, strlen($s1)-$idx));
return strrev(substr($s1, $idx, strlen($s1) - $idx));
}
/*
* Static method to demonstrate this class.
*/
public static function test() {
public static function test()
{
// A few examples.
echo "Testing CPENamingBind...<br>\n";
$wfn = new WellFormedName("a", "microsoft", "internet_explorer", "8\\.0\\.6001",
"beta", new LogicalValue("ANY"), "sp2", null, null, null, null);
$wfn2 = new WellFormedName();
$wfn2->set("part", "a");
$wfn2->set("vendor", "foo\\\$bar");
$wfn2->set("product", "insight");
$wfn2->set("version", "7\\.4\\.0\\.1570");
$wfn2->set("target_sw", "win2003");
$wfn2->set("update", new LogicalValue("NA"));
$wfn2->set("sw_edition", "online");
$wfn2->set("target_hw", "x64");
$cpenb = new CPENameBinder();
echo $cpenb->bindToURI($wfn) . "<br>\n";
echo $cpenb->bindToFS($wfn2) . "<br>\n";
echo "Testing CPENamingBind...<br>\n";
$wfn = new WellFormedName("a", "microsoft", "internet_explorer", "8\\.0\\.6001", "beta", new LogicalValue("ANY"), "sp2", null, null, null, null);
$wfn2 = new WellFormedName();
$wfn2->set("part", "a");
$wfn2->set("vendor", "foo\\\$bar");
$wfn2->set("product", "insight");
$wfn2->set("version", "7\\.4\\.0\\.1570");
$wfn2->set("target_sw", "win2003");
$wfn2->set("update", new LogicalValue("NA"));
$wfn2->set("sw_edition", "online");
$wfn2->set("target_hw", "x64");
$cpenb = new CPENameBinder();
echo $cpenb->bindToURI($wfn) . "<br>\n";
echo $cpenb->bindToFS($wfn2) . "<br>\n";
}
}

View File

@ -0,0 +1,466 @@
<?php
namespace PacificSec\CPE\Naming;
use PacificSec\CPE\Common\WellFormedName;
use PacificSec\CPE\Common\Utilities;
use PacificSec\CPE\Common\LogicalValue;
use \Exception;
/**
* The CPENameUnBinder class is a simple implementation
* of the CPE Name unbinding algorithm, as specified in the
* CPE Naming Standard version 2.3. It is based on Java version
* implemented by Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class CPENameUnbinder {
/**
* Top level function used to unbind a URI to a WFN.
* @param $uri string representing the URI to be unbound.
* @return WellFormedName representing the unbound URI.
* @throws Exception representing parsing errors.
*/
public function unbindURI($uri) {
// Validate the URI
Utilities::validateURI($uri);
// Initialize the empty WFN.
$result = new WellFormedName();
for ($i = 0; $i != 8; $i++) {
// get the i'th component of uri
$v = $this->getCompURI($uri, $i);
switch ($i) {
case 1:
$result->set("part", $this->decode($v));
break;
case 2:
$result->set("vendor", $this->decode($v));
break;
case 3:
$result->set("product", $this->decode($v));
break;
case 4:
$result->set("version", $this->decode($v));
break;
case 5:
$result->set("update", $this->decode($v));
break;
case 6:
// Special handling for edition component.
// Unpack edition if needed.
if ($v == "" || $v == "-"
|| substr($v, 0, 1) != "~") {
// Just a logical value or a non-packed value.
// So unbind to legacy edition, leaving other
// extended attributes unspecified.
$result->set("edition", $this->decode($v));
} else {
// We have five values packed together here.
$this->unpack($v, $result);
}
break;
case 7:
$result->set("language", $this->decode($v));
break;
}
}
return $result;
}
/**
* Top level function to unbind a formatted string to WFN.
* @param string $fs Formatted string to unbind
* @return WellFormedName
* @throws Exception representing parsing error
*/
public function unbindFS($fs) {
// Validate the formatted string
Utilities::validateFS($fs);
// Initialize empty WFN
$result = new WellFormedName();
// The cpe scheme is the 0th component, the cpe version is the 1st.
// So we start parsing at the 2nd component.
for ($a = 2; $a != 13; $a++) {
// Get the a'th string field.
$v = $this->getCompFS($fs, $a);
// Unbind the string.
$v = $this->unbindValueFS($v);
// Set the value of the corresponding attribute.
switch ($a) {
case 2:
$result->set("part", $v);
break;
case 3:
$result->set("vendor", $v);
break;
case 4:
$result->set("product", $v);
break;
case 5:
$result->set("version", $v);
break;
case 6:
$result->set("update", $v);
break;
case 7:
$result->set("edition", $v);
break;
case 8:
$result->set("language", $v);
break;
case 9:
$result->set("sw_edition", $v);
break;
case 10:
$result->set("target_sw", $v);
break;
case 11:
$result->set("target_hw", $v);
break;
case 12:
$result->set("other", $v);
break;
}
}
return $result;
}
/**
* Returns the i'th field of the formatted string. The colon is the field
* delimiter unless prefixed by a backslash.
* @param string $fs formatted string to retrieve from
* @param int $i index of field to retrieve from fs.
* @return int value of index of formatted string
*/
private function getCompFS($fs, $i) {
if ($i == 0) {
// return the substring from index 0 to the first occurence of an
// unescaped colon
$colon_idx = Utilities::getUnescapedColonIndex($fs);
// If no colon is found, we are at the end of the formatted string,
// so just return what's left.
if ($colon_idx == 0) {
return $fs;
}
return substr($fs, 0, $colon_idx);
} else {
$substrStart = Utilities::getUnescapedColonIndex($fs) + 1;
$substrLength = strlen($fs) - $substrStart;
return $this->getCompFS(substr($fs, $substrStart, $substrLength), $i - 1);
}
}
/**
* Takes a string value and returns the appropriate logical value if string
* is the bound form of a logical value. If string is some general value
* string, add quoting of non-alphanumerics as needed.
* @param string $s value to be unbound
* @return string logical value or quoted string
* @throws Exception representing parsing errors
*/
private function unbindValueFS($s) {
if ($s == "*") {
return new LogicalValue("ANY");
}
if ($s == "-") {
return new LogicalValue("NA");
}
return $this->addQuoting($s);
}
/**
* Inspect each character in a string, copying quoted characters, with
* their escaping, into the result. Look for unquoted non alphanumerics
* and if not "*" or "?", add escaping.
* @param $s
* @return
* @throws Exception representing parsing errors.
*/
private function addQuoting($s) {
$result = "";
$idx = 0;
$embedded = false;
while ($idx < strlen($s)) {
$c = substr($s, $idx, 1);
if (Utilities::isAlphanum($c)) {
// Alphanumeric characters pass untouched.
$result .= $c;
$idx = $idx + 1;
$embedded = true;
continue;
}
if ($c == "\\") {
// Anything quoted in the bound string stays quoted in the
// unbound string.
$result .= substr($s, $idx, 2);
$idx = $idx + 2;
$embedded = true;
continue;
}
if ($c == "*") {
// An unquoted asterisk must appear at the beginning or the end
// of the string.
if ($idx == 0 || $idx == strlen($s) - 1) {
$result .= $c;
$idx = $idx + 1;
$embedded = true;
continue;
} else {
throw new Exception("Error! cannot have unquoted * embedded in formatted string.", 0);
}
}
if ($c == "?") {
// An unquoted question mark must appear at the beginning or
// end of the string, or in a leading or trailing sequence.
if ( // ? legal at beginning or end
(($idx == 0) || ($idx == (strlen($s) - 1)))
// embedded is false, so must be preceded by ?
|| (!$embedded && (substr($s, $idx - 1, 1) == "?"))
// embedded is true, so must be followed by ?
|| ($embedded && (substr($s, $idx + 1, 1) == "?"))) {
$result .= $c;
$idx = $idx + 1;
$embedded = false;
continue;
} else {
throw new Exception("Error! cannot have unquoted ? embedded in formatted string.", 0);
}
}
// All other characters must be quoted.
$result .= "\\" . $c;
$idx = $idx + 1;
$embedded = true;
}
return $result;
}
/**
* Return the i'th component of the URI.
* @param $uri string representation of URI to retrieve components from.
* @param int $i Index of component to return.
* @return mixed If i = 0, returns the URI scheme. Otherwise, returns the i'th
* component of uri.
*/
private function getCompURI($uri, $i) {
if ($i == 0) {
return substr($uri, $i, strpos($uri, "/"));
}
$sa = explode(":", $uri);
// If requested component exceeds the number
// of components in URI, return blank
if ($i >= sizeof($sa)) {
return "";
}
if ($i === 1) {
return substr($sa[$i], 1, strlen($sa[$i])-1);
}
return $sa[$i];
}
/**
* Scans a string and returns a copy with all percent-encoded characters
* decoded. This function is the inverse of pctEncode() defined in the
* CPENameBinder class. Only legal percent-encoded forms are decoded.
* Others raise a ParseException.
* @param $s string to be decoded
* @return string decoded string
* @throws Exception representing parsing errors
* @see CPENameBinder#pctEncode
*/
private function decode($s) {
if ($s == "") {
return new LogicalValue("ANY");
}
if ($s == "-") {
return new LogicalValue("NA");
}
// Start the scanning loop.
// Normalize: convert all uppercase letters to lowercase first.
$s = strtolower($s);
$result = "";
$idx = 0;
$embedded = false;
while ($idx < strlen($s)) {
// Get the idx'th character of s.
$c = substr($s, $idx, 1);
// Deal with dot, hyphen, and tilde: decode with quoting.
if ($c == "." || $c == "-" || $c == "~") {
$result .= "\\" . $c;
$idx = $idx + 1;
// a non-%01 encountered.
$embedded = true;
continue;
}
if ($c != "%") {
$result .= $c;
$idx = $idx + 1;
// a non-%01 encountered.
$embedded = true;
continue;
}
// We get here if we have a substring starting w/ '%'.
$form = substr($s, $idx, 3);
if ($form == "%01") {
if (($idx == 0)
|| ($idx == strlen($s) - 3)
|| (!$embedded && substr($s, $idx - 3, 2) == "%01")
|| ($embedded && (strlen($s) >= $idx + 6))
&& (substr($s, $idx + 3, 3) == "%01")) {
$result .= "?";
$idx = $idx + 3;
continue;
} else {
throw new Exception("Error decoding string", 0);
}
} else if ($form == "%02") {
if (($idx == 0) || ($idx == (strlen($s) - 3))) {
$result .= "*";
} else {
throw new Exception("Error decoding string", 0);
}
} else if ($form == "%21") {
$result .= "\\!";
} else if ($form == "%22") {
$result .= "\\\"";
} else if ($form == "%23") {
$result .= "\\#";
} else if ($form == "%24") {
$result .= "\\$";
} else if ($form == "%25") {
$result .= "\\%";
} else if ($form == "%26") {
$result .= "\\&";
} else if ($form == "%27") {
$result .= "\\'";
} else if ($form == "%28") {
$result .= "\\(";
} else if ($form == "%29") {
$result .= "\\)";
} else if ($form == "%2a") {
$result .= "\\*";
} else if ($form == "%2b") {
$result .= "\\+";
} else if ($form == "%2c") {
$result .= "\\,";
} else if ($form == "%2f") {
$result .= "\\/";
} else if ($form == "%3a") {
$result .= "\\:";
} else if ($form == "%3b") {
$result .= "\\;";
} else if ($form == "%3c") {
$result .= "\\<";
} else if ($form == "%3d") {
$result .= "\\=";
} else if ($form == "%3e") {
$result .= "\\>";
} else if ($form == "%3f") {
$result .= "\\?";
} else if ($form == "%40") {
$result .= "\\@";
} else if ($form == "%5b") {
$result .= "\\[";
} else if ($form == "%5c") {
$result .= "\\\\";
} else if ($form == "%5d") {
$result .= "\\]";
} else if ($form == "%5e") {
$result .= "\\^";
} else if ($form == "%60") {
$result .= "\\`";
} else if ($form == "%7b") {
$result .= "\\{";
} else if ($form == "%7c") {
$result .= "\\|";
} else if ($form == "%7d") {
$result .= "\\}";
} else if ($form == "%7e") {
$result .= "\\~";
} else {
throw new Exception("Unknown form: " . $form, 0);
}
$idx = $idx + 3;
$embedded = true;
}
return $result;
}
/**
* Unpacks the elements in s and sets the attributes in the given
* WellFormedName accordingly.
* @param string $s packed string
* @param $wfn WellFormedName
* @return WellFormedName The augmented WellFormedName.
*/
private function unpack($s, WellFormedName $wfn) {
// Parse out the five elements.
$start = 1;
$ed = ""; $sw_edition = ""; $t_sw = ""; $t_hw = ""; $oth = "";
$end = strpos($s, "~", $start);
if ($start == $end) {
$ed = "";
} else {
$ed = substr($s, $start, $end-$start);
}
$start = $end + 1;
$end = strpos($s, "~", $start);
if ($start == $end) {
$sw_edition = "";
} else {
$sw_edition = substr($s, $start, $end-$start);
}
$start = $end + 1;
$end = strpos($s, "~", $start);
if ($start == $end) {
$t_sw = "";
} else {
$t_sw = substr($s, $start, $end-$start);
}
$start = $end + 1;
$end = strpos($s, "~", $start);
if ($start == $end) {
$t_hw = "";
} else {
$t_hw = substr($s, $start, $end-$start);
}
$start = $end + 1;
if ($start >= strlen($s)) {
$oth = "";
} else {
$oth = substr($s, $start, strlen($s) - 1 - $start);
}
// Set each component in the WFN.
try {
$wfn->set("edition", $this->decode($ed));
$wfn->set("sw_edition", $this->decode($sw_edition));
$wfn->set("target_sw", $this->decode($t_sw));
$wfn->set("target_hw", $this->decode($t_hw));
$wfn->set("other", $this->decode($oth));
} catch (Exception $e) {
echo $e->getMessage() . "\n";
}
return $wfn;
}
/*
* Static method to demonstrate this class.
*/
public static function test() {
// A few examples.
echo "Testing CPENamingUnbind...<br>\n";
$cpenu = new CPENameUnbinder();
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer%01%01%01%01:?:beta");
echo $wfn . "<br>\n";
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer:8.%2a:sp%3f");
echo $wfn . "<br>\n";
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer:8.%02:sp%01");
echo $wfn . "<br>\n";
$wfn = $cpenu->unbindURI("cpe:/a:hp:insight_diagnostics:7.4.0.1570::~~online~win2003~x64~");
echo $wfn . "<br>\n";
echo $cpenu->unbindFS("cpe:2.3:a:micr\\?osoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*") . "<br>\n";
}
}

View File

@ -1,42 +0,0 @@
<?php
namespace PacificSec\CPE\Common;
/**
* This class represents a Logical Value. It is based on Java version
* implemented by JKRAUNELIS <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class LogicalValue {
private $any = false;
private $na = false;
// Object must be constructed with the string "ANY" or "NA".
public function __construct($type) {
if ($type == "ANY") {
$this->any = true;
} else if ($type == "NA") {
$this->na = true;
} else {
throw new Exception("LogicalValue must be ANY or NA");
}
}
public function isANY(){
return $this->any;
}
public function isNA(){
return $this->na;
}
public function __toString(){
if ($this->any){
return "ANY";
}
return "NA";
}
}

View File

@ -1,167 +0,0 @@
<?php
namespace PacificSec\CPE\Common;
use \Exception;
/**
* A collection of utility functions for use with the matching and
* naming namespaces. It is based on Java version implemented by
* Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class Utilities {
/**
* Searches string for special characters * and ?
* @param $string to be searched
* @return true if string contains wildcard, false otherwise
*/
public static function containsWildcards($string) {
if (strpos($string, "*") !== false || strpos($string, "?") !== false) {
if (!(strpos($string, "\\") !== false)) {
return true;
}
return false;
}
return false;
}
/**
* Checks if given number is even or not
* @param $num number to check
* @return true if number is even, false if not
*/
public static function isEvenNumber($num) {
return (is_int($num) && $num % 2 == 0);
}
/**
* Counts the number of escape characters in the string beginning and ending
* at the given indices
* @param $str string to search
* @param $start beginning index
* @param $end ending index
* @return number of escape characters in string
* @todo fix the use of $str. The Java version is also not using this variable.
*/
public static function countEscapeCharacters($str, $start, $end) {
$result = 0;
$active = false;
$i = 0;
while ($i < $end) {
if ($active && ($i >= $start)) {
$result = $result + 1;
}
$i = $i + 1;
}
return $result;
}
/**
* Searches a string for the first unescaped colon and returns the index of
* that colon
* @param $str string to search
* @return index of first unescaped colon, or 0 if not found
*/
public static function getUnescapedColonIndex($str) {
$found = false;
$colon_idx = 0;
$start_idx = 0;
// Find the first non-escaped colon.
while (!$found) {
$colon_idx = strpos($str, ":", $start_idx + 1);
// If no colon is found, return 0.
if ($colon_idx === false) {
return 0;
}
// Peek at character before colon.
if (substr($str, $colon_idx-1, 1) == "\\") {
// If colon is escaped, keep looking.
$start_idx = $colon_idx;
} else {
$found = true;
}
}
return $colon_idx;
}
/**
* Returns true if the string contains only
* alphanumeric characters or the underscore character,
* false otherwise.
* @param $c the string in question
* @return true if $c is alphanumeric or underscore, false if not
*/
public static function isAlphanum($c) {
return (preg_match("/^[a-zA-Z0-9]$/", $c) || $c == "_");
}
/**
* This function is not part of the reference implementation pseudo code
* found in the CPE 2.3 specification. It enforces two rules in the
* specification:
* URI must start with the characters "cpe:/"
* A URI may not contain more than 7 components
* If either rule is violated, a Exception is thrown.
* @param $in string with URI to be validated
*/
public static function validateURI($in) {
// make sure uri starts with cpe:/
if (strpos(strtolower($in), "cpe:/") !== 0) {
throw new Exception("Error: URI must start with 'cpe:/'. Given: " . $in, 0);
}
// make sure uri doesn't contain more than 7 colons
$count = sizeof(explode(":", $in));
if ($count > 8) {
throw new Exception("Error parsing URI. Found " . ($count - 8) . " extra components in: " . $in, 0);
}
}
/**
* This function is not part of the reference implementation pseudo code
* found in the CPE 2.3 specification. It enforces three rules found in the
* specification:
* Formatted string must start with the characters "cpe:2.3:"
* A formatted string must contain 11 components
* A formatted string must not contain empty components
* If any rule is violated, a ParseException is thrown.
* @param $in string with FS to be validated
*/
public static function validateFS($in) {
if (strpos(strtolower($in), "cpe:2.3:") !== 0) {
throw new Exception("Error: Formatted String must start with \"cpe:2.3\". Given: " . $in, 0);
}
$count = 0;
for ($i = 0; $i != strlen($in); $i++){
if (substr($in, $i, 1) == ":"){
if (substr($in, $i - 1, 1) != "\\"){
$count++;
}
if (($i+1) < strlen($in) && substr($in, $i+1, 1) == ":"){
throw new Exception("Error parsing formatted string. Found empty component", 0);
}
}
}
if ($count > 12){
$extra = $count - 12;
$s = "Error parsing formatted string. Found " . $extra . " extra component";
if ($extra > 1){
$s = $s . "s";
}
$s = $s . " in: " . $in;
throw new Exception($s, 0);
}
if ($count < 12){
$missing = 12 - $count;
$s = "Error parsing formatted string. Missing " . $missing . " component";
if ($missing > 1){
$s = $s . "s";
}
throw new Exception($s, 0);
}
}
}

View File

@ -1,210 +0,0 @@
<?php
namespace PacificSec\CPE\Common;
use \Exception;
/**
* The WellFormedName class represents a Well Formed Name, as defined
* in the CPE Specification version 2.3. It is based on Java version
* implemented by jkraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for details.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class WellFormedName {
// Underlying wfn representation.
private $wfn = null;
// All permissible WFN attributes as defined by specification.
const ATTRIBUTES = array("part", "vendor", "product", "version",
"update", "edition", "language", "sw_edition", "target_sw",
"target_hw", "other");
/**
* Constructs a new WellFormedName object, setting each component to the
* given parameter value. If a parameter is null, the component is set to
* the default value "ANY".
* @param $part string representing the part component
* @param $vendor string representing the vendor component
* @param $product string representing the product component
* @param $version string representing the version component
* @param $update string representing the update component
* @param $edition string representing the edition component
* @param $language string representing the language component
* @param $sw_edition string representing the sw_edition component
* @param $target_sw string representing the target_sw component
* @param $target_hw string representing the target_hw component
* @param $other string representing the other component
*/
public function __construct($part = null, $vendor = null, $product = null, $version = null,
$update = null, $edition = null, $language = null, $sw_edition = null, $target_sw = null,
$target_hw = null, $other = null) {
$this->wfn = array();
// Constructs a new WellFormedName object, with all components set to the default value "ANY".
if ($part === null && $vendor === null && $product === null && $version === null &&
$update === null && $edition === null && $language === null && $sw_edition === null && $target_sw === null &&
$target_hw === null && $other === null){
foreach (WellFormedName::ATTRIBUTES as $a){
if ($a != "part"){
$this->set($a, new LogicalValue("ANY"));
}
}
return;
}
$this->set("part", $part);
$this->set("vendor", $vendor);
$this->set("product", $product);
$this->set("version", $version);
$this->set("update", $update);
$this->set("edition", $edition);
$this->set("language", $language);
$this->set("sw_edition", $sw_edition);
$this->set("target_sw", $target_sw);
$this->set("target_hw", $target_hw);
$this->set("other", $other);
}
/**
* @param $attribute string representing the component value to get
* @return the string value of the given component, or default value "ANY"
* if the component does not exist
*/
public function get($attribute){
if (array_key_exists($attribute, $this->wfn))
return $this->wfn[$attribute];
else
return new LogicalValue("ANY");
}
/**
* Sets the given attribute to value, if the attribute is in the list of
* permissible components
* @param $attribute string representing the component to set
* @param $value object or string representing the value of the given component
*/
public final function set($attribute, $value){
// Iterate over permissible attributes.
foreach (WellFormedName::ATTRIBUTES as $a){
// If the argument is a valid attribute, set that attribute's value.
if ($attribute == $a) {
// check to see if we're setting a LogicalValue ANY or NA
if ($value instanceof LogicalValue){
// don't allow logical values in part component
if ($attribute == "part"){
var_dump($value); echo "<br>\n";
var_dump($a); echo "<br>\n";
var_dump($attribute); echo "<br>\n";
throw new Exception("Error! part component cannot be a logical value");
}
// put the Object in the ht and break
$this->wfn[$attribute] = $value;
break;
}
if ($value == null || $value == ""){
// if value is null or blank, set attribute to default logical ANY
$this->wfn[$attribute] = new LogicalValue("ANY");
break;
}
$svalue = $value;
// Reg exs
// check for printable characters - no control characters
if (!preg_match("/^[[:print:]]*$/", $svalue)){
throw new Exception("Error! encountered non printable character in: " . $svalue, 0);
}
// svalue has whitespace
if (preg_match("/^.*\\s+.*$/", $svalue)){
throw new Exception("Error! component cannot contain whitespace: " . $svalue, 0);
}
// svalue has more than one unquoted star
if (preg_match("/^\\*{2,}.*$/", $svalue) || preg_match("/^.*\\*{2,}$/", $svalue)){
throw new Exception("Error! component cannot contain more than one * in sequence: " . $svalue, 0);
}
// svalue has unquoted punctuation embedded
if (preg_match("/^.*(?<!\\\\)[\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\+\\,\\.\\/\\:\\;\\<\\=\\>\\@\\[\\]\\^\\`\\{\\|\\}\\~\\-].*$/", $svalue)) {
throw new Exception("Error! component cannot contain unquoted punctuation: " . $svalue, 0);
}
// svalue has an unquoted *
if (preg_match("/^.+(?<!\\\\)[\\*].+$/", $svalue)) {
throw new Exception("Error! component cannot contain embedded *: " . $svalue, 0);
}
// svalue has embedded unquoted ?
// this will catch a single unquoted ?, so make sure we deal with that
if (strpos($svalue, "?") !== false) {
if ($svalue == "?") {
// single ? is valid
$this->wfn[$attribute] = $svalue;
break;
}
// remove leading and trailing ?s
$v = $svalue;
while (strpos($v, "?") === 0) {
// remove all leading ?'s
$v = substr($v, 1);
}
$v = strrev($v);
while (strpos($v, "?") === 0) {
// remove all trailing ?'s (string has been reversed)
$v = substr($v, 1);
}
// back to normal
$v = strrev($v);
// after leading and trailing ?s are removed, check if value
// contains unquoted ?s
if (preg_match("/^.+(?<!\\\\)[\\?].+$/", $v)) {
throw new Exception("Error! component cannot contain embedded ?: " . $svalue, 0);
}
}
// single asterisk is not allowed
if ($svalue == "*") {
throw new Exception("Error! component cannot be a single *: " . $svalue, 0);
}
// quoted hyphen not allowed by itself
if ($svalue == "-") {
throw new Exception("Error! component cannot be quoted hyphen: " . $svalue, 0);
}
// part must be a, o, or h
if ($attribute == "part") {
if ($svalue != "a" && $svalue != "o" && $svalue != "h") {
throw new Exception("Error! part component must be one of the following: 'a', 'o', 'h': " . $svalue, 0);
}
}
// should be good to go
$this->wfn[$attribute] = $svalue;
break;
}
}
}
/**
*
* @return string representation of the WellFormedName
*/
public function __toString() {
$str = "wfn:[";
foreach (WellFormedName::ATTRIBUTES as $attr) {
$str = $str . $attr;
$str = $str . "=";
$o = $this->wfn[$attr];
if ($o instanceof LogicalValue) {
$str = $str . $o;
$str = $str . ", ";
} else {
$str = $str . "\"";
$str = $str . $o;
$str = $str . "\", ";
}
}
$str = substr($str, 0, strlen($str)-1);
$str = substr($str, 0, strlen($str)-1);
$str = $str . "]";
return $str;
}
}

View File

@ -1,287 +0,0 @@
<?php
namespace PacificSec\CPE\Matching;
use PacificSec\CPE\Common\WellFormedName;
use PacificSec\CPE\Common\Utilities;
use PacificSec\CPE\Common\LogicalValue;
use PacificSec\CPE\Naming\CPENameBinder;
use PacificSec\CPE\Naming\CPENameUnbinder;
/**
* The CPENameMatcher is an implementation of the CPE Matching algorithm,
* as specified in the CPE Matching Standard version 2.3. It is based on
* Java version implemented by Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class CPENameMatcher {
/**
* Tests two Well Formed Names for disjointness.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the names are disjoint, false otherwise
*/
public function isDisjoint(WellFormedName $source, WellFormedName $target) {
// if any pairwise comparison is disjoint, the names are disjoint.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result == Relation::DISJOINT)
return true;
}
return false;
}
/**
* Tests two Well Formed Names for equality.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the names are equal, false otherwise
*/
public function isEqual(WellFormedName $source, WellFormedName $target) {
// if every pairwise comparison is equal, the names are equal.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::EQUAL){
return false;
}
}
return true;
}
/**
* Tests if the target Well Formed Name is a subset of the source Well Formed
* Name.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the target is a subset of the source, false otherwise
*/
public function isSubset(WellFormedName $source, WellFormedName $target) {
// if any comparison is anything other than subset or equal, then target is
// not a subset of source.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::SUBSET && $result != Relation::EQUAL) {
return false;
}
}
return true;
}
/**
* Tests if the target Well Formed name is a superset of the source Well Formed
* Name.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return true if the target is a superset of the source, false otherwise
*/
public function isSuperset(WellFormedName $source, WellFormedName $target) {
// if any comparison is anything other than superset or equal, then target is not
// a superset of source.
$resultList = $this->compareWFNs($source, $target);
foreach ($resultList as $result){
if ($result != Relation::SUPERSET && $result != Relation::EQUAL) {
return false;
}
}
return true;
}
/**
* Compares each attribute value pair in two Well Formed Names.
* @param $source WellFormedName Source WFN
* @param $target WellFormedName Target WFN
* @return A array mapping attribute string to attribute value Relation
*/
public function compareWFNs(WellFormedName $source, WellFormedName $target) {
$result = array();
$result["part"] = $this->compare($source->get("part"), $target->get("part"));
$result["vendor"] = $this->compare($source->get("vendor"), $target->get("vendor"));
$result["product"] = $this->compare($source->get("product"), $target->get("product"));
$result["version"] = $this->compare($source->get("version"), $target->get("version"));
$result["update"] = $this->compare($source->get("update"), $target->get("update"));
$result["edition"] = $this->compare($source->get("edition"), $target->get("edition"));
$result["language"] = $this->compare($source->get("language"), $target->get("language"));
$result["sw_edition"] = $this->compare($source->get("sw_edition"), $target->get("sw_edition"));
$result["target_sw"] = $this->compare($source->get("target_sw"), $target->get("target_sw"));
$result["target_hw"] = $this->compare($source->get("target_hw"), $target->get("target_hw"));
$result["other"] = $this->compare($source->get("other"), $target->get("other"));
return $result;
}
/**
* Compares an attribute value pair.
* @param $source Source attribute value.
* @param $target Target attribute value.
* @return The relation between the two attribute values.
*/
private function compare($source, $target) {
// matching is case insensitive, convert strings to lowercase.
if ($this->isString($source)) {
$source = strtolower($source);
}
if ($this->isString($target)) {
$target = strtolower($target);
}
// Unquoted wildcard characters yield an undefined result.
if ($this->isString($target) && Utilities::containsWildcards($target)) {
return Relation::UNDEFINED;
}
// If source and target values are equal, then result is equal.
if ($source == $target) {
return Relation::EQUAL;
}
// Check to see if source or target are Logical Values.
$lvSource = null;
$lvTarget = null;
if ($source instanceof LogicalValue) {
$lvSource = $source;
}
if ($target instanceof LogicalValue) {
$lvTarget = $target;
}
if ($lvSource != null && $lvTarget != null) {
// If Logical Values are equal, result is equal.
if ($lvSource->isANY() == $lvTarget->isANY() || $lvSource->isNA() == $lvTarget->isNA()) {
return Relation::EQUAL;
}
}
// If source value is ANY, result is a superset.
if ($lvSource != null) {
if ($lvSource->isANY()) {
return Relation::SUPERSET;
}
}
// If target value is ANY, result is a subset.
if ($lvTarget != null) {
if ($lvTarget->isANY()) {
return Relation::SUBSET;
}
}
// If source or target is NA, result is disjoint.
if ($lvSource != null) {
if ($lvSource->isNA()) {
return Relation::DISJOINT;
}
}
if ($lvTarget != null) {
if ($lvTarget->isNA()) {
return Relation::DISJOINT;
}
}
// only Strings will get to this point, not LogicalValues
return $this->compareStrings($source, $target);
}
/**
* Compares a source string to a target string, and addresses the condition
* in which the source string includes unquoted special characters. It
* performs a simple regular expression match, with the assumption that
* (as required) unquoted special characters appear only at the beginning
* and/or the end of the source string. It also properly differentiates
* between unquoted and quoted special characters.
*
* @param $source string Source attribute value.
* @param $target string Target attribute value.
* @return Relation between source and target Strings.
*/
private function compareStrings($source, $target) {
$start = 0;
$end = strlen($source);
$begins = 0;
$ends = 0;
$index = 0; $leftover = 0; $escapes = 0;
if (substr($source, 0, 1) == "*") {
$start = 1;
$begins = -1;
} else {
while (($start < strlen($source)) && (substr($source, $start, 1) == "?")) {
$start = $start + 1;
$begins = $begins + 1;
}
}
if ((substr($source, $end - 1, 1) == "*") && ($this->isEvenWildcards($source, $end - 1))) { //TODO
$end = $end - 1;
$ends = -1;
} else {
while (($end > 0) && substr($source, $end - 1, 1) == "?" && ($this->isEvenWildcards($source, $end - 1))) { //TODO
$end = $end - 1;
$ends = $ends + 1;
}
}
$source = substr($source, $start, $end-$start);
$index = -1;
$leftover = strlen($target);
while ($leftover > 0) {
$index = strpos($target, $source, $index + 1);
if ($index === false) {
break;
}
$escapes = Utilities::countEscapeCharacters($target, 0, $index);
if (($index > 0) && ($begins != -1) && ($begins < ($index - $escapes))) {
break;
}
$escapes = Utilities::countEscapeCharacters($target, $index + 1, strlen($target));
$leftover = strlen($target) - $index - $escapes - strlen($source);
if (($leftover > 0) && (($ends != -1) && ($leftover > $ends))) {
continue;
}
return Relation::SUPERSET;
}
return Relation::DISJOINT;
}
/**
* Searches a string for the backslash character
* @param $str string to search in
* @param $idx end index
* @return true if the number of backslash characters is even, false if odd
*/
private function isEvenWildcards($str, $idx) {
$result = 0;
while (($idx > 0) && (strpos($str, "\\", $idx - 1)) !== false) {
$idx = $idx - 1;
$result = $result + 1;
}
return Utilities::isEvenNumber($result);
}
/**
* Tests if an Object is an instance of the String class
* @param $arg the var to test
* @return true if arg is a string, false if not
*/
private function isString($arg) {
is_string($arg);
}
/*
* Static method to demonstrate this class.
*/
public static function test() {
// Examples.
$wfn = new WellFormedName("a", "microsoft", "internet_explorer", "8\\.0\\.6001", "beta", new LogicalValue("ANY"), "sp2", null, null, null, null);
$wfn2 = new WellFormedName("a", "microsoft", "internet_explorer", new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"), new LogicalValue("ANY"));
$cpenm = new CPENameMatcher();
$cpenu = new CPENameUnbinder();
$cpenb = new CPENameBinder();
$wfn = $cpenu->unbindURI($cpenb->bindToURI($wfn));
$wfn2 = $cpenu->unbindFS($cpenb->bindToFS($wfn2));
var_dump($cpenm->isDisjoint($wfn, $wfn2)); // false
var_dump($cpenm->isEqual($wfn, $wfn2)); // false
var_dump($cpenm->isSubset($wfn, $wfn2)); // true, $wfn2 is a subset of wfn
var_dump($cpenm->isSuperset($wfn, $wfn2)); // false
$wfn = $cpenu->unbindFS("cpe:2.3:a:adobe:*:9.*:*:PalmOS:*:*:*:*:*");
$wfn2 = $cpenu->unbindURI("cpe:/a::Reader:9.3.2:-:-");
var_dump($cpenm->isDisjoint($wfn, $wfn2)); // true, $wfn2 and wfn are disjoint
var_dump($cpenm->isEqual($wfn, $wfn2)); // false
var_dump($cpenm->isSubset($wfn, $wfn2)); // false
var_dump($cpenm->isSuperset($wfn, $wfn2)); // false
}
}

View File

@ -1,466 +0,0 @@
<?php
namespace PacificSec\CPE\Naming;
use PacificSec\CPE\Common\WellFormedName;
use PacificSec\CPE\Common\Utilities;
use PacificSec\CPE\Common\LogicalValue;
use \Exception;
/**
* The CPENameUnBinder class is a simple implementation
* of the CPE Name unbinding algorithm, as specified in the
* CPE Naming Standard version 2.3. It is based on Java version
* implemented by Joshua Kraunelis <jkraunelis@mitre.org>.
*
* @see <a href="http://cpe.mitre.org">cpe.mitre.org</a> for more information.
* @author Antonio Franco
* @email antonio.franco@pacificsec.com
*/
class CPENameUnbinder {
/**
* Top level function used to unbind a URI to a WFN.
* @param $uri string representing the URI to be unbound.
* @return WellFormedName representing the unbound URI.
* @throws Exception representing parsing errors.
*/
public function unbindURI($uri) {
// Validate the URI
Utilities::validateURI($uri);
// Initialize the empty WFN.
$result = new WellFormedName();
for ($i = 0; $i != 8; $i++) {
// get the i'th component of uri
$v = $this->getCompURI($uri, $i);
switch ($i) {
case 1:
$result->set("part", $this->decode($v));
break;
case 2:
$result->set("vendor", $this->decode($v));
break;
case 3:
$result->set("product", $this->decode($v));
break;
case 4:
$result->set("version", $this->decode($v));
break;
case 5:
$result->set("update", $this->decode($v));
break;
case 6:
// Special handling for edition component.
// Unpack edition if needed.
if ($v == "" || $v == "-"
|| substr($v, 0, 1) != "~") {
// Just a logical value or a non-packed value.
// So unbind to legacy edition, leaving other
// extended attributes unspecified.
$result->set("edition", $this->decode($v));
} else {
// We have five values packed together here.
$this->unpack($v, $result);
}
break;
case 7:
$result->set("language", $this->decode($v));
break;
}
}
return $result;
}
/**
* Top level function to unbind a formatted string to WFN.
* @param $fs Formatted string to unbind
* @return WellFormedName
* @throws Exception representing parsing error
*/
public function unbindFS($fs) {
// Validate the formatted string
Utilities::validateFS($fs);
// Initialize empty WFN
$result = new WellFormedName();
// The cpe scheme is the 0th component, the cpe version is the 1st.
// So we start parsing at the 2nd component.
for ($a = 2; $a != 13; $a++) {
// Get the a'th string field.
$v = $this->getCompFS($fs, $a);
// Unbind the string.
$v = $this->unbindValueFS($v);
// Set the value of the corresponding attribute.
switch ($a) {
case 2:
$result->set("part", $v);
break;
case 3:
$result->set("vendor", $v);
break;
case 4:
$result->set("product", $v);
break;
case 5:
$result->set("version", $v);
break;
case 6:
$result->set("update", $v);
break;
case 7:
$result->set("edition", $v);
break;
case 8:
$result->set("language", $v);
break;
case 9:
$result->set("sw_edition", $v);
break;
case 10:
$result->set("target_sw", $v);
break;
case 11:
$result->set("target_hw", $v);
break;
case 12:
$result->set("other", $v);
break;
}
}
return $result;
}
/**
* Returns the i'th field of the formatted string. The colon is the field
* delimiter unless prefixed by a backslash.
* @param $fs formatted string to retrieve from
* @param $i index of field to retrieve from fs.
* @return value of index of formatted string
*/
private function getCompFS($fs, $i) {
if ($i == 0) {
// return the substring from index 0 to the first occurence of an
// unescaped colon
$colon_idx = Utilities::getUnescapedColonIndex($fs);
// If no colon is found, we are at the end of the formatted string,
// so just return what's left.
if ($colon_idx == 0) {
return $fs;
}
return substr($fs, 0, $colon_idx);
} else {
$substrStart = Utilities::getUnescapedColonIndex($fs) + 1;
$substrLength = strlen($fs) - $substrStart;
return $this->getCompFS(substr($fs, $substrStart, $substrLength), $i - 1);
}
}
/**
* Takes a string value and returns the appropriate logical value if string
* is the bound form of a logical value. If string is some general value
* string, add quoting of non-alphanumerics as needed.
* @param $s value to be unbound
* @return logical value or quoted string
* @throws Exception representing parsing errors
*/
private function unbindValueFS($s) {
if ($s == "*") {
return new LogicalValue("ANY");
}
if ($s == "-") {
return new LogicalValue("NA");
}
return $this->addQuoting($s);
}
/**
* Inspect each character in a string, copying quoted characters, with
* their escaping, into the result. Look for unquoted non alphanumerics
* and if not "*" or "?", add escaping.
* @param $s
* @return
* @throws Exception representing parsing errors.
*/
private function addQuoting($s) {
$result = "";
$idx = 0;
$embedded = false;
while ($idx < strlen($s)) {
$c = substr($s, $idx, 1);
if (Utilities::isAlphanum($c) || $c == "_") {
// Alphanumeric characters pass untouched.
$result = $result . $c;
$idx = $idx + 1;
$embedded = true;
continue;
}
if ($c == "\\") {
// Anything quoted in the bound string stays quoted in the
// unbound string.
$result = $result . substr($s, $idx, 2);
$idx = $idx + 2;
$embedded = true;
continue;
}
if ($c == "*") {
// An unquoted asterisk must appear at the beginning or the end
// of the string.
if ($idx == 0 || $idx == strlen($s) - 1) {
$result = $result . $c;
$idx = $idx + 1;
$embedded = true;
continue;
} else {
throw new Exception("Error! cannot have unquoted * embedded in formatted string.", 0);
}
}
if ($c == "?") {
// An unquoted question mark must appear at the beginning or
// end of the string, or in a leading or trailing sequence.
if ( // ? legal at beginning or end
(($idx == 0) || ($idx == (strlen($s) - 1)))
// embedded is false, so must be preceded by ?
|| (!$embedded && (substr($s, $idx - 1, 1) == "?"))
// embedded is true, so must be followed by ?
|| ($embedded && (substr($s, $idx + 1, 1) == "?"))) {
$result = $result . $c;
$idx = $idx + 1;
$embedded = false;
continue;
} else {
throw new Exception("Error! cannot have unquoted ? embedded in formatted string.", 0);
}
}
// All other characters must be quoted.
$result = $result . "\\" . $c;
$idx = $idx + 1;
$embedded = true;
}
return $result;
}
/**
* Return the i'th component of the URI.
* @param $uri string representation of URI to retrieve components from.
* @param $i Index of component to return.
* @return If i = 0, returns the URI scheme. Otherwise, returns the i'th
* component of uri.
*/
private function getCompURI($uri, $i) {
if ($i == 0) {
return substr($uri, $i, strpos($uri, "/"));
}
$sa = explode(":", $uri);
// If requested component exceeds the number
// of components in URI, return blank
if ($i >= sizeof($sa)) {
return "";
}
if ($i === 1) {
return substr($sa[$i], 1, strlen($sa[$i])-1);
}
return $sa[$i];
}
/**
* Scans a string and returns a copy with all percent-encoded characters
* decoded. This function is the inverse of pctEncode() defined in the
* CPENameBinder class. Only legal percent-encoded forms are decoded.
* Others raise a ParseException.
* @param $s string to be decoded
* @return decoded string
* @throws Exception representing parsing errors
* @see CPENameBinder#pctEncode
*/
private function decode($s) {
if ($s == "") {
return new LogicalValue("ANY");
}
if ($s == "-") {
return new LogicalValue("NA");
}
// Start the scanning loop.
// Normalize: convert all uppercase letters to lowercase first.
$s = strtolower($s);
$result = "";
$idx = 0;
$embedded = false;
while ($idx < strlen($s)) {
// Get the idx'th character of s.
$c = substr($s, $idx, 1);
// Deal with dot, hyphen, and tilde: decode with quoting.
if ($c == "." || $c == "-" || $c == "~") {
$result = $result . "\\" . $c;
$idx = $idx + 1;
// a non-%01 encountered.
$embedded = true;
continue;
}
if ($c != "%") {
$result = $result . $c;
$idx = $idx + 1;
// a non-%01 encountered.
$embedded = true;
continue;
}
// We get here if we have a substring starting w/ '%'.
$form = substr($s, $idx, 3);
if ($form == "%01") {
if (($idx == 0)
|| ($idx == strlen($s) - 3)
|| (!$embedded && substr($s, $idx - 3, 2) == "%01")
|| ($embedded && (strlen($s) >= $idx + 6))
&& (substr($s, $idx + 3, 3) == "%01")) {
$result = $result . "?";
$idx = $idx + 3;
continue;
} else {
throw new Exception("Error decoding string", 0);
}
} else if ($form == "%02") {
if (($idx == 0) || ($idx == (strlen($s) - 3))) {
$result = $result . "*";
} else {
throw new Exception("Error decoding string", 0);
}
} else if ($form == "%21") {
$result = $result . "\\!";
} else if ($form == "%22") {
$result = $result . "\\\"";
} else if ($form == "%23") {
$result = $result . "\\#";
} else if ($form == "%24") {
$result = $result . "\\$";
} else if ($form == "%25") {
$result = $result . "\\%";
} else if ($form == "%26") {
$result = $result . "\\&";
} else if ($form == "%27") {
$result = $result . "\\'";
} else if ($form == "%28") {
$result = $result . "\\(";
} else if ($form == "%29") {
$result = $result . "\\)";
} else if ($form == "%2a") {
$result = $result . "\\*";
} else if ($form == "%2b") {
$result = $result . "\\+";
} else if ($form == "%2c") {
$result = $result . "\\,";
} else if ($form == "%2f") {
$result = $result . "\\/";
} else if ($form == "%3a") {
$result = $result . "\\))";
} else if ($form == "%3b") {
$result = $result . "\\;";
} else if ($form == "%3c") {
$result = $result . "\\<";
} else if ($form == "%3d") {
$result = $result . "\\=";
} else if ($form == "%3e") {
$result = $result . "\\>";
} else if ($form == "%3f") {
$result = $result . "\\?";
} else if ($form == "%40") {
$result = $result . "\\@";
} else if ($form == "%5b") {
$result = $result . "\\[";
} else if ($form == "%5c") {
$result = $result . "\\\\";
} else if ($form == "%5d") {
$result = $result . "\\]";
} else if ($form == "%5e") {
$result = $result . "\\^";
} else if ($form == "%60") {
$result = $result . "\\`";
} else if ($form == "%7b") {
$result = $result . "\\{";
} else if ($form == "%7c") {
$result = $result . "\\|";
} else if ($form == "%7d") {
$result = $result . "\\}";
} else if ($form == "%7e") {
$result = $result . "\\~";
} else {
throw new Exception("Unknown form: " . $form, 0);
}
$idx = $idx + 3;
$embedded = true;
}
return $result;
}
/**
* Unpacks the elements in s and sets the attributes in the given
* WellFormedName accordingly.
* @param $s packed string
* @param $wfn WellFormedName
* @return The augmented WellFormedName.
*/
private function unpack($s, WellFormedName $wfn) {
// Parse out the five elements.
$start = 1;
$ed = ""; $sw_edition = ""; $t_sw = ""; $t_hw = ""; $oth = "";
$end = strpos($s, "~", $start);
if ($start == $end) {
$ed = "";
} else {
$ed = substr($s, $start, $end-$start);
}
$start = $end + 1;
$end = strpos($s, "~", $start);
if ($start == $end) {
$sw_edition = "";
} else {
$sw_edition = substr($s, $start, $end-$start);
}
$start = $end + 1;
$end = strpos($s, "~", $start);
if ($start == $end) {
$t_sw = "";
} else {
$t_sw = substr($s, $start, $end-$start);
}
$start = $end + 1;
$end = strpos($s, "~", $start);
if ($start == $end) {
$t_hw = "";
} else {
$t_hw = substr($s, $start, $end-$start);
}
$start = $end + 1;
if ($start >= strlen($s)) {
$oth = "";
} else {
$oth = substr($s, $start, strlen($s) - 1 - $start);
}
// Set each component in the WFN.
try {
$wfn->set("edition", $this->decode($ed));
$wfn->set("sw_edition", $this->decode($sw_edition));
$wfn->set("target_sw", $this->decode($t_sw));
$wfn->set("target_hw", $this->decode($t_hw));
$wfn->set("other", $this->decode($oth));
} catch (Exception $e) {
echo $e->getMessage() . "\n";
}
return $wfn;
}
/*
* Static method to demonstrate this class.
*/
public static function test() {
// A few examples.
echo "Testing CPENamingUnbind...<br>\n";
$cpenu = new CPENameUnbinder();
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer%01%01%01%01:?:beta");
echo $wfn . "<br>\n";
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer:8.%2a:sp%3f");
echo $wfn . "<br>\n";
$wfn = $cpenu->unbindURI("cpe:/a:microsoft:internet_explorer:8.%02:sp%01");
echo $wfn . "<br>\n";
$wfn = $cpenu->unbindURI("cpe:/a:hp:insight_diagnostics:7.4.0.1570::~~online~win2003~x64~");
echo $wfn . "<br>\n";
echo $cpenu->unbindFS("cpe:2.3:a:micr\\?osoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*") . "<br>\n";
}
}

View File

@ -0,0 +1,24 @@
<?php
use Sami\RemoteRepository\GitHubRemoteRepository;
use Sami\Sami;
use Sami\Version\GitVersionCollection;
use Symfony\Component\Finder\Finder;
$iterator = Finder::create()
->files()
->name('*.php')
->in($dir = __DIR__ . '/src');
$versions = GitVersionCollection::create($dir)
->addFromTags(function ($version) {
return preg_match('~^\d+\.\d+\.\d+$~', $version);
})
->add('master');
return new Sami($iterator, [
'title' => 'PhpSpreadsheet',
'versions' => $versions,
'build_dir' => __DIR__ . '/build/%version%',
'cache_dir' => __DIR__ . '/cache/%version%',
'remote_repository' => new GitHubRemoteRepository('PHPOffice/PhpSpreadsheet', dirname($dir)),
]);

View File

@ -10,6 +10,7 @@ php:
cache:
directories:
- cache
- vendor
- $HOME/.composer/cache
@ -28,7 +29,7 @@ jobs:
php: 7.1
script:
- ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run
- ./vendor/bin/phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=samples/Header.php --standard=PSR2 -n
- ./vendor/bin/phpcs --report-width=200 samples/ src/ tests/ --ignore=samples/Header.php --standard=PSR2 -n
- stage: Coverage
php: 7.1
@ -38,3 +39,21 @@ jobs:
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover tests/coverage-clover.xml
- stage: API documentation
php: 7.1
before_script:
- curl -O http://get.sensiolabs.org/sami.phar
script:
- git fetch origin master:master
- git fetch origin --tags
- php sami.phar update .sami.php
- echo '<html><head><meta http-equiv="Refresh" content="0; url=master/"></head><body><p>If you are not automatically redirected, please go to <a href="master/">the latest stable API documentation</a>.</p></body></html>' > build/index.html
deploy:
provider: pages
skip-cleanup: true
local-dir: build
github-token: $GITHUB_TOKEN
on:
all_branches: true
condition: $TRAVIS_BRANCH =~ ^master|develop$

View File

@ -5,6 +5,95 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.4.0] - 2018-08-06
### Added
- Add excel function EXACT(value1, value2) support - [#595](https://github.com/PHPOffice/PhpSpreadsheet/pull/595)
- Support workbook view attributes for Xlsx format - [#523](https://github.com/PHPOffice/PhpSpreadsheet/issues/523)
- Read and write hyperlink for drawing image - [#490](https://github.com/PHPOffice/PhpSpreadsheet/pull/490)
- Added calculation engine support for the new bitwise functions that were added in MS Excel 2013
- BITAND() Returns a Bitwise 'And' of two numbers
- BITOR() Returns a Bitwise 'Or' of two number
- BITXOR() Returns a Bitwise 'Exclusive Or' of two numbers
- BITLSHIFT() Returns a number shifted left by a specified number of bits
- BITRSHIFT() Returns a number shifted right by a specified number of bits
- Added calculation engine support for other new functions that were added in MS Excel 2013 and MS Excel 2016
- Text Functions
- CONCAT() Synonym for CONCATENATE()
- NUMBERVALUE() Converts text to a number, in a locale-independent way
- UNICHAR() Synonym for CHAR() in PHPSpreadsheet, which has always used UTF-8 internally
- UNIORD() Synonym for ORD() in PHPSpreadsheet, which has always used UTF-8 internally
- TEXTJOIN() Joins together two or more text strings, separated by a delimiter
- Logical Functions
- XOR() Returns a logical Exclusive Or of all arguments
- Date/Time Functions
- ISOWEEKNUM() Returns the ISO 8601 week number of the year for a given date
- Lookup and Reference Functions
- FORMULATEXT() Returns a formula as a string
- Financial Functions
- PDURATION() Calculates the number of periods required for an investment to reach a specified value
- RRI() Calculates the interest rate required for an investment to grow to a specified future value
- Engineering Functions
- ERF.PRECISE() Returns the error function integrated between 0 and a supplied limit
- ERFC.PRECISE() Synonym for ERFC
- Math and Trig Functions
- SEC() Returns the secant of an angle
- SECH() Returns the hyperbolic secant of an angle
- CSC() Returns the cosecant of an angle
- CSCH() Returns the hyperbolic cosecant of an angle
- COT() Returns the cotangent of an angle
- COTH() Returns the hyperbolic cotangent of an angle
- ACOT() Returns the cotangent of an angle
- ACOTH() Returns the hyperbolic cotangent of an angle
- Refactored Complex Engineering Functions to use external complex number library
- Added calculation engine support for the new complex number functions that were added in MS Excel 2013
- IMCOSH() Returns the hyperbolic cosine of a complex number
- IMCOT() Returns the cotangent of a complex number
- IMCSC() Returns the cosecant of a complex number
- IMCSCH() Returns the hyperbolic cosecant of a complex number
- IMSEC() Returns the secant of a complex number
- IMSECH() Returns the hyperbolic secant of a complex number
- IMSINH() Returns the hyperbolic sine of a complex number
- IMTAN() Returns the tangent of a complex number
### Fixed
- Fix ISFORMULA() function to work with a cell reference to another worksheet
- Xlsx reader crashed when reading a file with workbook protection - [#553](https://github.com/PHPOffice/PhpSpreadsheet/pull/553)
- Cell formats with escaped spaces were causing incorrect date formatting - [#557](https://github.com/PHPOffice/PhpSpreadsheet/issues/557)
- Could not open CSV file containing HTML fragment - [#564](https://github.com/PHPOffice/PhpSpreadsheet/issues/564)
- Exclude the vendor folder in migration - [#481](https://github.com/PHPOffice/PhpSpreadsheet/issues/481)
- Chained operations on cell ranges involving borders operated on last cell only [#428](https://github.com/PHPOffice/PhpSpreadsheet/issues/428)
- Avoid memory exhaustion when cloning worksheet with a drawing [#437](https://github.com/PHPOffice/PhpSpreadsheet/issues/437)
- Migration tool keep variables containing $PHPExcel untouched [#598](https://github.com/PHPOffice/PhpSpreadsheet/issues/598)
- Rowspans/colspans were incorrect when adding worksheet using loadIntoExisting [#619](https://github.com/PHPOffice/PhpSpreadsheet/issues/619)
## [1.3.1] - 2018-06-12
### Fixed
- Ranges across Z and AA columns incorrectly threw an exception - [#545](https://github.com/PHPOffice/PhpSpreadsheet/issues/545)
## [1.3.0] - 2018-06-10
### Added
- Support to read Xlsm templates with form elements, macros, printer settings, protected elements and back compatibility drawing, and save result without losing important elements of document - [#435](https://github.com/PHPOffice/PhpSpreadsheet/issues/435)
- Expose sheet title maximum length as `Worksheet::SHEET_TITLE_MAXIMUM_LENGTH` - [#482](https://github.com/PHPOffice/PhpSpreadsheet/issues/482)
- Allow escape character to be set in CSV reader [#492](https://github.com/PHPOffice/PhpSpreadsheet/issues/492)
### Fixed
- Subtotal 9 in a group that has other subtotals 9 exclude the totals of the other subtotals in the range - [#332](https://github.com/PHPOffice/PhpSpreadsheet/issues/332)
- `Helper\Html` support UTF-8 HTML input - [#444](https://github.com/PHPOffice/PhpSpreadsheet/issues/444)
- Xlsx loaded an extra empty comment for each real comment - [#375](https://github.com/PHPOffice/PhpSpreadsheet/issues/375)
- Xlsx reader do not read rows and columns filtered out in readFilter at all - [#370](https://github.com/PHPOffice/PhpSpreadsheet/issues/370)
- Make newer Excel versions properly recalculate formulas on document open - [#456](https://github.com/PHPOffice/PhpSpreadsheet/issues/456)
- `Coordinate::extractAllCellReferencesInRange()` throws an exception for an invalid range [#519](https://github.com/PHPOffice/PhpSpreadsheet/issues/519)
- Fixed parsing of conditionals in COUNTIF functions - [#526](https://github.com/PHPOffice/PhpSpreadsheet/issues/526)
- Corruption errors for saved Xlsx docs with frozen panes - [#532](https://github.com/PHPOffice/PhpSpreadsheet/issues/532)
## [1.2.1] - 2018-04-10
### Fixed

View File

@ -18,9 +18,7 @@ PhpSpreadsheet is a library written in pure PHP and providing a set of classes t
## Documentation
Read more about it, including install instructions, in the official documentation:
https://phpspreadsheet.readthedocs.io
Read more about it, including install instructions, in the [official documentation](https://phpspreadsheet.readthedocs.io). Or check out the [API documentation](https://phpoffice.github.io/PhpSpreadsheet/master).
Please ask your support questions on [StackOverflow](http://stackoverflow.com/questions/tagged/phpspreadsheet), or have a quick chat on [Gitter](https://gitter.im/PHPOffice/PhpSpreadsheet).

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