diff --git a/README.md b/README.md index f4698da..3d73128 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PHP-CRUD-API -Single file PHP 7 script that adds a REST API to a MySQL/MariaDB, PostgreSQL, SQL Server or SQLite database. +Single file PHP script that adds a REST API to a MySQL/MariaDB, PostgreSQL, SQL Server or SQLite database. NB: This is the [TreeQL](https://treeql.org) reference implementation in PHP. @@ -55,6 +55,9 @@ Alternatively you can integrate this project into the web framework of your choi In these integrations [Composer](https://getcomposer.org/) is used to load this project as a dependency. +For people that don't use composer, the file "`api.include.php`" is provided. This file contains everything +from "`api.php`" except the configuration from "`src/index.php`" and can be used by PHP's "include". + ## Configuration Edit the following lines in the bottom of the file "`api.php`": @@ -1207,7 +1210,7 @@ I am testing mainly on Ubuntu and I have the following test setups: - (Docker) Ubuntu 18.04 with PHP 7.2, MySQL 5.7, PostgreSQL 10.4 (PostGIS 2.4) and SQLite 3.22 - (Docker) Debian 10 with PHP 7.3, MariaDB 10.3, PostgreSQL 11.4 (PostGIS 2.5) and SQLite 3.27 - (Docker) Ubuntu 20.04 with PHP 7.4, MySQL 8.0, PostgreSQL 12.2 (PostGIS 3.0) and SQLite 3.31 - - (Docker) CentOS 8 with PHP 7.4, MariaDB 10.5, PostgreSQL 12.5 (PostGIS 3.0) and SQLite 3.26 + - (Docker) CentOS 8 with PHP 8.0, MariaDB 10.5, PostgreSQL 12.5 (PostGIS 3.0) and SQLite 3.26 This covers not all environments (yet), so please notify me of failing tests and report your environment. I will try to cover most relevant setups in the "docker" folder of the project. @@ -1261,17 +1264,17 @@ Install docker using the following commands and then logout and login for the ch To run the docker tests run "build_all.sh" and "run_all.sh" from the docker directory. The output should be: ================================================ - CentOS 8 (PHP 7.4) + CentOS 8 (PHP 8.0) ================================================ [1/4] Starting MariaDB 10.5 ..... done [2/4] Starting PostgreSQL 12.5 .. done [3/4] Starting SQLServer 2017 ... skipped [4/4] Cloning PHP-CRUD-API v2 ... skipped ------------------------------------------------ - mysql: 110 tests ran in 1911 ms, 1 skipped, 0 failed - pgsql: 110 tests ran in 1112 ms, 1 skipped, 0 failed + mysql: 110 tests ran in 957 ms, 1 skipped, 0 failed + pgsql: 110 tests ran in 817 ms, 1 skipped, 0 failed sqlsrv: skipped, driver not loaded - sqlite: 110 tests ran in 1178 ms, 12 skipped, 0 failed + sqlite: 110 tests ran in 685 ms, 12 skipped, 0 failed ================================================ Debian 10 (PHP 7.3) ================================================ @@ -1280,10 +1283,10 @@ To run the docker tests run "build_all.sh" and "run_all.sh" from the docker dire [3/4] Starting SQLServer 2017 ... skipped [4/4] Cloning PHP-CRUD-API v2 ... skipped ------------------------------------------------ - mysql: 110 tests ran in 3459 ms, 1 skipped, 0 failed - pgsql: 110 tests ran in 1134 ms, 1 skipped, 0 failed + mysql: 110 tests ran in 952 ms, 1 skipped, 0 failed + pgsql: 110 tests ran in 816 ms, 1 skipped, 0 failed sqlsrv: skipped, driver not loaded - sqlite: 110 tests ran in 1275 ms, 12 skipped, 0 failed + sqlite: 110 tests ran in 690 ms, 12 skipped, 0 failed ================================================ Debian 9 (PHP 7.0) ================================================ @@ -1292,10 +1295,10 @@ To run the docker tests run "build_all.sh" and "run_all.sh" from the docker dire [3/4] Starting SQLServer 2017 ... skipped [4/4] Cloning PHP-CRUD-API v2 ... skipped ------------------------------------------------ - mysql: 110 tests ran in 3181 ms, 1 skipped, 0 failed - pgsql: 110 tests ran in 1201 ms, 1 skipped, 0 failed + mysql: 110 tests ran in 1075 ms, 1 skipped, 0 failed + pgsql: 110 tests ran in 834 ms, 1 skipped, 0 failed sqlsrv: skipped, driver not loaded - sqlite: 110 tests ran in 1414 ms, 12 skipped, 0 failed + sqlite: 110 tests ran in 728 ms, 12 skipped, 0 failed ================================================ Ubuntu 16.04 (PHP 7.0) ================================================ @@ -1304,9 +1307,9 @@ To run the docker tests run "build_all.sh" and "run_all.sh" from the docker dire [3/4] Starting SQLServer 2017 ... done [4/4] Cloning PHP-CRUD-API v2 ... skipped ------------------------------------------------ - mysql: 110 tests ran in 3168 ms, 1 skipped, 0 failed - pgsql: 110 tests ran in 1197 ms, 1 skipped, 0 failed - sqlsrv: 110 tests ran in 10151 ms, 1 skipped, 0 failed + mysql: 110 tests ran in 1065 ms, 1 skipped, 0 failed + pgsql: 110 tests ran in 845 ms, 1 skipped, 0 failed + sqlsrv: 110 tests ran in 5404 ms, 1 skipped, 0 failed sqlite: skipped, driver not loaded ================================================ Ubuntu 18.04 (PHP 7.2) @@ -1316,10 +1319,10 @@ To run the docker tests run "build_all.sh" and "run_all.sh" from the docker dire [3/4] Starting SQLServer 2017 ... skipped [4/4] Cloning PHP-CRUD-API v2 ... skipped ------------------------------------------------ - mysql: 110 tests ran in 3709 ms, 1 skipped, 0 failed - pgsql: 110 tests ran in 1334 ms, 1 skipped, 0 failed + mysql: 110 tests ran in 1261 ms, 1 skipped, 0 failed + pgsql: 110 tests ran in 859 ms, 1 skipped, 0 failed sqlsrv: skipped, driver not loaded - sqlite: 110 tests ran in 1477 ms, 12 skipped, 0 failed + sqlite: 110 tests ran in 725 ms, 12 skipped, 0 failed ================================================ Ubuntu 20.04 (PHP 7.4) ================================================ @@ -1328,10 +1331,10 @@ To run the docker tests run "build_all.sh" and "run_all.sh" from the docker dire [3/4] Starting SQLServer 2017 ... skipped [4/4] Cloning PHP-CRUD-API v2 ... skipped ------------------------------------------------ - mysql: 110 tests ran in 5102 ms, 1 skipped, 0 failed - pgsql: 110 tests ran in 1170 ms, 1 skipped, 0 failed + mysql: 110 tests ran in 1505 ms, 1 skipped, 0 failed + pgsql: 110 tests ran in 851 ms, 1 skipped, 0 failed sqlsrv: skipped, driver not loaded - sqlite: 110 tests ran in 1380 ms, 12 skipped, 0 failed + sqlite: 110 tests ran in 675 ms, 12 skipped, 0 failed The above test run (including starting up the databases) takes less than 5 minutes on my slow laptop. @@ -1351,10 +1354,10 @@ The above test run (including starting up the databases) takes less than 5 minut [3/4] Starting SQLServer 2017 ... skipped [4/4] Cloning PHP-CRUD-API v2 ... skipped ------------------------------------------------ - mysql: 105 tests ran in 3390 ms, 1 skipped, 0 failed - pgsql: 105 tests ran in 936 ms, 1 skipped, 0 failed + mysql: 110 tests ran in 1261 ms, 1 skipped, 0 failed + pgsql: 110 tests ran in 859 ms, 1 skipped, 0 failed sqlsrv: skipped, driver not loaded - sqlite: 105 tests ran in 1063 ms, 12 skipped, 0 failed + sqlite: 110 tests ran in 725 ms, 12 skipped, 0 failed root@b7ab9472e08f:/php-crud-api# As you can see the "run.sh" script gives you access to a prompt in a chosen the docker environment. diff --git a/api.include.php b/api.include.php index 868dc65..0e866ac 100644 --- a/api.include.php +++ b/api.include.php @@ -6387,7 +6387,7 @@ namespace Tqdev\PhpCrudApi\Database { return $this->pdo()->lastInsertId($name); } - public function query(string $statement): \PDOStatement + public function query($query, /* ?int */$fetchMode = null, ...$fetchModeArgs): \PDOStatement { return call_user_func_array(array($this->pdo(), 'query'), func_get_args()); } @@ -7065,7 +7065,7 @@ namespace Tqdev\PhpCrudApi\Middleware\Router { $method = strtoupper($request->getMethod()); $path = array(); $segment = $method; - for ($i = 1; $segment; $i++) { + for ($i = 1; strlen($segment) > 0; $i++) { array_push($path, $segment); $segment = RequestUtils::getPathSegment($request, $i); } @@ -7579,6 +7579,7 @@ namespace Tqdev\PhpCrudApi\Middleware { $columnNames = array_map('trim', explode(',', $returnedColumns)); $columnNames[] = $passwordColumnName; $columnNames[] = $pkName; + $columnNames = array_values(array_unique($columnNames)); } $columnOrdering = $this->ordering->getDefaultColumnOrdering($table); if ($path == 'register') { @@ -8745,7 +8746,11 @@ namespace Tqdev\PhpCrudApi\Middleware { private function xml2json($xml) { - $a = @dom_import_simplexml(simplexml_load_string($xml)); + $o = @simplexml_load_string($xml); + if ($o===false) { + return null; + } + $a = @dom_import_simplexml($o); if (!$a) { return null; } diff --git a/api.php b/api.php index 7d777bb..49430c7 100644 --- a/api.php +++ b/api.php @@ -6387,7 +6387,7 @@ namespace Tqdev\PhpCrudApi\Database { return $this->pdo()->lastInsertId($name); } - public function query(string $statement): \PDOStatement + public function query($query, /* ?int */$fetchMode = null, ...$fetchModeArgs): \PDOStatement { return call_user_func_array(array($this->pdo(), 'query'), func_get_args()); } @@ -7065,7 +7065,7 @@ namespace Tqdev\PhpCrudApi\Middleware\Router { $method = strtoupper($request->getMethod()); $path = array(); $segment = $method; - for ($i = 1; $segment; $i++) { + for ($i = 1; strlen($segment) > 0; $i++) { array_push($path, $segment); $segment = RequestUtils::getPathSegment($request, $i); } @@ -7579,6 +7579,7 @@ namespace Tqdev\PhpCrudApi\Middleware { $columnNames = array_map('trim', explode(',', $returnedColumns)); $columnNames[] = $passwordColumnName; $columnNames[] = $pkName; + $columnNames = array_values(array_unique($columnNames)); } $columnOrdering = $this->ordering->getDefaultColumnOrdering($table); if ($path == 'register') { @@ -8745,7 +8746,11 @@ namespace Tqdev\PhpCrudApi\Middleware { private function xml2json($xml) { - $a = @dom_import_simplexml(simplexml_load_string($xml)); + $o = @simplexml_load_string($xml); + if ($o===false) { + return null; + } + $a = @dom_import_simplexml($o); if (!$a) { return null; } diff --git a/docker-compose.yml b/docker-compose.yml index 405da65..cc7ed6f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,3 +29,5 @@ services: - "8080:80" depends_on: - database + #volumes: + #- .:/php-crud-api:ro diff --git a/docker/centos8/Dockerfile b/docker/centos8/Dockerfile index 625fdfc..59bc59e 100644 --- a/docker/centos8/Dockerfile +++ b/docker/centos8/Dockerfile @@ -16,10 +16,10 @@ RUN dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x # enable epel repo RUN dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm # enable powertools repos -RUN dnf -y install 'dnf-command(config-manager)' && dnf -y config-manager --set-enabled PowerTools +RUN dnf -y install 'dnf-command(config-manager)' && dnf -y config-manager --set-enabled powertools -# set php to remi 7.4 -RUN dnf -y module reset php && dnf -y module enable php:remi-7.4 +# set php to remi 8.0 +RUN dnf -y module reset php && dnf -y module enable php:remi-8.0 # disable mariadb and postgresql default (appstream) repo RUN dnf -y module disable mariadb RUN dnf -y module disable postgresql diff --git a/docker/centos8/run.sh b/docker/centos8/run.sh index 189abe8..8dc71e4 100755 --- a/docker/centos8/run.sh +++ b/docker/centos8/run.sh @@ -1,6 +1,6 @@ #!/bin/bash echo "================================================" -echo " CentOS 8 (PHP 7.4)" +echo " CentOS 8 (PHP 8.0)" echo "================================================" echo -n "[1/4] Starting MariaDB 10.5 ..... " # initialize mysql diff --git a/src/Tqdev/PhpCrudApi/Database/LazyPdo.php b/src/Tqdev/PhpCrudApi/Database/LazyPdo.php index 87c2797..b0a6c21 100644 --- a/src/Tqdev/PhpCrudApi/Database/LazyPdo.php +++ b/src/Tqdev/PhpCrudApi/Database/LazyPdo.php @@ -117,7 +117,7 @@ class LazyPdo extends \PDO return $this->pdo()->lastInsertId($name); } - public function query(string $statement): \PDOStatement + public function query($query, /* ?int */$fetchMode = null, ...$fetchModeArgs): \PDOStatement { return call_user_func_array(array($this->pdo(), 'query'), func_get_args()); } diff --git a/src/Tqdev/PhpCrudApi/Middleware/DbAuthMiddleware.php b/src/Tqdev/PhpCrudApi/Middleware/DbAuthMiddleware.php index 91d4180..5e96567 100644 --- a/src/Tqdev/PhpCrudApi/Middleware/DbAuthMiddleware.php +++ b/src/Tqdev/PhpCrudApi/Middleware/DbAuthMiddleware.php @@ -63,6 +63,7 @@ class DbAuthMiddleware extends Middleware $columnNames = array_map('trim', explode(',', $returnedColumns)); $columnNames[] = $passwordColumnName; $columnNames[] = $pkName; + $columnNames = array_values(array_unique($columnNames)); } $columnOrdering = $this->ordering->getDefaultColumnOrdering($table); if ($path == 'register') { diff --git a/src/Tqdev/PhpCrudApi/Middleware/Router/SimpleRouter.php b/src/Tqdev/PhpCrudApi/Middleware/Router/SimpleRouter.php index b8360ac..b1a5c75 100644 --- a/src/Tqdev/PhpCrudApi/Middleware/Router/SimpleRouter.php +++ b/src/Tqdev/PhpCrudApi/Middleware/Router/SimpleRouter.php @@ -104,7 +104,7 @@ class SimpleRouter implements Router $method = strtoupper($request->getMethod()); $path = array(); $segment = $method; - for ($i = 1; $segment; $i++) { + for ($i = 1; strlen($segment) > 0; $i++) { array_push($path, $segment); $segment = RequestUtils::getPathSegment($request, $i); } diff --git a/src/Tqdev/PhpCrudApi/Middleware/XmlMiddleware.php b/src/Tqdev/PhpCrudApi/Middleware/XmlMiddleware.php index b613ce1..b2225e4 100644 --- a/src/Tqdev/PhpCrudApi/Middleware/XmlMiddleware.php +++ b/src/Tqdev/PhpCrudApi/Middleware/XmlMiddleware.php @@ -83,7 +83,11 @@ class XmlMiddleware extends Middleware private function xml2json($xml) { - $a = @dom_import_simplexml(simplexml_load_string($xml)); + $o = @simplexml_load_string($xml); + if ($o===false) { + return null; + } + $a = @dom_import_simplexml($o); if (!$a) { return null; } diff --git a/tests/functional/001_records/003_read_post.log b/tests/functional/001_records/003_read_post.log index 8cb9d44..86c05c6 100644 --- a/tests/functional/001_records/003_read_post.log +++ b/tests/functional/001_records/003_read_post.log @@ -6,3 +6,11 @@ Content-Type: application/json; charset=utf-8 Content-Length: 58 {"id":2,"user_id":1,"category_id":2,"content":"It works!"} +=== +GET /records/posts/0 +=== +404 +Content-Type: application/json; charset=utf-8 +Content-Length: 46 + +{"code":1003,"message":"Record '0' not found"}