Skip to content

Commit 60dcde4

Browse files
committed
Merge branch 'master' of github.com:mevdschee/php-crud-api
2 parents ba2c841 + 6d9d724 commit 60dcde4

File tree

10 files changed

+88
-145
lines changed

10 files changed

+88
-145
lines changed

README.md

+36-21
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ There are also proof-of-concept ports of this script that only support basic RES
3333
- PostGIS 2.0 or higher for spatial features in PostgreSQL 9.1 or higher
3434
- SQL Server 2012 or higher (2017 for Linux support)
3535

36+
## Known issues
37+
38+
- Seeing integers as strings? Make sure to enable the `nd_pdo_mysql` extension and disable `pdo_mysql`.
39+
3640
## Installation
3741

3842
This is a single file application! Upload "`api.php`" somewhere and enjoy!
@@ -105,7 +109,7 @@ These features match features in v1 (see branch "v1"):
105109
- [x] Supports POST variables as input (x-www-form-urlencoded)
106110
- [x] Supports a JSON object as input
107111
- [x] Supports a JSON array as input (batch insert)
108-
- [x] Supports file upload from web forms (multipart/form-data)
112+
- [ ] ~~Supports file upload from web forms (multipart/form-data)~~
109113
- [ ] ~~Condensed JSON output: first row contains field names~~
110114
- [x] Sanitize and validate input using callbacks
111115
- [x] Permission system for databases, tables, columns and records
@@ -734,26 +738,7 @@ The above example will add a header "X-Time-Taken" with the number of seconds th
734738

735739
### File uploads
736740

737-
The 'fileUpload' middleware allows you to upload a file using a web form (multipart/form-data) like this:
738-
739-
```
740-
<form method="post" action="http://localhost/api.php/records/categories" enctype="multipart/form-data">
741-
Select image to upload:
742-
<input type="file" name="icon">
743-
<input type="submit">
744-
</form>
745-
```
746-
747-
Then this is handled as if you would have sent:
748-
749-
```
750-
POST http://localhost/api.php/records/categories
751-
{"icon_name":"not.gif","icon_type":"image\/gif","icon":"ZGF0YQ==","icon_error":0,"icon_size":4}
752-
```
753-
754-
As you can see the "xxx_name", "xxx_type", "xxx_error" and "xxx_size" meta fields are added (where "xxx" is the name of the file field).
755-
756-
NB: You cannot edit a file using this method, because browsers do not support the "PUT" method in these forms.
741+
File uploads are supported through the [FileReader API](https://caniuse.com/#feat=filereader).
757742

758743
## OpenAPI specification
759744

@@ -877,6 +862,36 @@ To run the functional tests locally you may run the following command:
877862
This runs the functional tests from the "tests" directory. It uses the database dumps (fixtures) and
878863
database configuration (config) from the corresponding subdirectories.
879864

865+
## Nginx config example
866+
```
867+
server {
868+
listen 80 default_server;
869+
listen [::]:80 default_server;
870+
871+
root /var/www/html;
872+
index index.php index.html index.htm index.nginx-debian.html;
873+
server_name server_domain_or_IP;
874+
875+
location / {
876+
try_files $uri $uri/ =404;
877+
}
878+
879+
location ~ [^/]\.php(/|$) {
880+
fastcgi_split_path_info ^(.+\.php)(/.+)$;
881+
try_files $fastcgi_script_name =404;
882+
set $path_info $fastcgi_path_info;
883+
fastcgi_param PATH_INFO $path_info;
884+
fastcgi_index index.php;
885+
include fastcgi.conf;
886+
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
887+
}
888+
889+
location ~ /\.ht {
890+
deny all;
891+
}
892+
}
893+
```
894+
880895
### Docker
881896

882897
Install docker using the following commands and then logout and login for the changes to take effect:

api.php

+29-49
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function __construct(String $prefix, String $config)
7575
$this->memcache->addServer($address, $port);
7676
}
7777

78-
protected function create(): stdClass
78+
protected function create() /*: \Memcache*/
7979
{
8080
return new \Memcache();
8181
}
@@ -100,7 +100,7 @@ public function clear(): bool
100100

101101
class MemcachedCache extends MemcacheCache
102102
{
103-
protected function create(): stdClass
103+
protected function create() /*: \Memcached*/
104104
{
105105
return new \Memcached();
106106
}
@@ -3188,35 +3188,6 @@ public function handle(Request $request): Response
31883188
}
31893189
}
31903190

3191-
// file: src/Tqdev/PhpCrudApi/Middleware/FileUploadMiddleware.php
3192-
3193-
class FileUploadMiddleware extends Middleware
3194-
{
3195-
public function handle(Request $request): Response
3196-
{
3197-
$files = $request->getUploadedFiles();
3198-
if (!empty($files)) {
3199-
$body = $request->getBody();
3200-
foreach ($files as $fieldName => $file) {
3201-
if (isset($file['error']) && $file['error']) {
3202-
return $this->responder->error(ErrorCode::FILE_UPLOAD_FAILED, $fieldName);
3203-
}
3204-
foreach ($file as $key => $value) {
3205-
if ($key == 'tmp_name') {
3206-
$value = base64_encode(file_get_contents($value));
3207-
$key = $fieldName;
3208-
} else {
3209-
$key = $fieldName . '_' . $key;
3210-
}
3211-
$body->$key = $value;
3212-
}
3213-
}
3214-
$request->setBody($body);
3215-
}
3216-
return $this->next->handle($request);
3217-
}
3218-
}
3219-
32203191
// file: src/Tqdev/PhpCrudApi/Middleware/FirewallMiddleware.php
32213192

32223193
class FirewallMiddleware extends Middleware
@@ -3266,6 +3237,30 @@ public function handle(Request $request): Response
32663237
}
32673238
}
32683239

3240+
// file: src/Tqdev/PhpCrudApi/Middleware/FormMiddleware.php
3241+
3242+
class FormMiddleware extends Middleware
3243+
{
3244+
public function handle(Request $request): Response
3245+
{
3246+
$body = $request->getBody();
3247+
if (!$body) {
3248+
$body = file_get_contents('php://input');
3249+
if ($body) {
3250+
parse_str($body, $input);
3251+
foreach ($input as $key => $value) {
3252+
if (substr($key, -9) == '__is_null') {
3253+
$input[substr($key, 0, -9)] = null;
3254+
unset($input[$key]);
3255+
}
3256+
}
3257+
$request->setBody((object) $input);
3258+
}
3259+
}
3260+
return $this->next->handle($request);
3261+
}
3262+
}
3263+
32693264
// file: src/Tqdev/PhpCrudApi/Middleware/JwtAuthMiddleware.php
32703265

32713266
class JwtAuthMiddleware extends Middleware
@@ -5070,9 +5065,6 @@ public function __construct(Config $config)
50705065
case 'jwtAuth':
50715066
new JwtAuthMiddleware($router, $responder, $properties);
50725067
break;
5073-
case 'fileUpload':
5074-
new FileUploadMiddleware($router, $responder, $properties);
5075-
break;
50765068
case 'validation':
50775069
new ValidationMiddleware($router, $responder, $properties, $reflection);
50785070
break;
@@ -5405,17 +5397,10 @@ private function decodeBody(String $body) /*: ?object*/
54055397

54065398
private function parseBody(String $body = null) /*: void*/
54075399
{
5408-
if ($body) {
5409-
$object = $this->decodeBody($body);
5410-
} else {
5411-
if (!empty($_FILES)) {
5412-
$object = (object) $_POST;
5413-
} else {
5414-
$input = file_get_contents('php://input');
5415-
$object = $this->decodeBody($input);
5416-
}
5400+
if (!$body) {
5401+
$body = file_get_contents('php://input');
54175402
}
5418-
$this->body = $object;
5403+
$this->body = $this->decodeBody($body);
54195404
}
54205405

54215406
public function getMethod(): String
@@ -5493,11 +5478,6 @@ public static function fromString(String $request): Request
54935478
}
54945479
return new Request($method, $path, $query, $headers, $body);
54955480
}
5496-
5497-
public function getUploadedFiles(): array
5498-
{
5499-
return $_FILES;
5500-
}
55015481
}
55025482

55035483
// file: src/Tqdev/PhpCrudApi/Response.php

examples/clients/upload/form.html

-12
This file was deleted.

src/Tqdev/PhpCrudApi/Api.php

-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use Tqdev\PhpCrudApi\Middleware\BasicAuthMiddleware;
1515
use Tqdev\PhpCrudApi\Middleware\CorsMiddleware;
1616
use Tqdev\PhpCrudApi\Middleware\CustomizationMiddleware;
17-
use Tqdev\PhpCrudApi\Middleware\FileUploadMiddleware;
1817
use Tqdev\PhpCrudApi\Middleware\FirewallMiddleware;
1918
use Tqdev\PhpCrudApi\Middleware\JwtAuthMiddleware;
2019
use Tqdev\PhpCrudApi\Middleware\MultiTenancyMiddleware;
@@ -60,9 +59,6 @@ public function __construct(Config $config)
6059
case 'jwtAuth':
6160
new JwtAuthMiddleware($router, $responder, $properties);
6261
break;
63-
case 'fileUpload':
64-
new FileUploadMiddleware($router, $responder, $properties);
65-
break;
6662
case 'validation':
6763
new ValidationMiddleware($router, $responder, $properties, $reflection);
6864
break;

src/Tqdev/PhpCrudApi/Cache/MemcacheCache.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function __construct(String $prefix, String $config)
2222
$this->memcache->addServer($address, $port);
2323
}
2424

25-
protected function create(): stdClass
25+
protected function create() /*: \Memcache*/
2626
{
2727
return new \Memcache();
2828
}

src/Tqdev/PhpCrudApi/Cache/MemcachedCache.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
class MemcachedCache extends MemcacheCache
55
{
6-
protected function create(): stdClass
6+
protected function create() /*: \Memcached*/
77
{
88
return new \Memcached();
99
}

src/Tqdev/PhpCrudApi/Middleware/FileUploadMiddleware.php

-33
This file was deleted.

src/Tqdev/PhpCrudApi/Record/Condition/Condition.php

+10-9
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public static function fromString(ReflectedTable $table, String $value): Conditi
3333
if (count($parts) < 2) {
3434
return null;
3535
}
36+
if (count($parts) < 3) {
37+
$parts[2] = '';
38+
}
3639
$field = $table->getColumn($parts[0]);
3740
$command = $parts[1];
3841
$negate = false;
@@ -47,15 +50,13 @@ public static function fromString(ReflectedTable $table, String $value): Conditi
4750
$command = substr($command, 1);
4851
}
4952
}
50-
if (count($parts) == 3 || (count($parts) == 2 && in_array($command, ['ic', 'is', 'iv']))) {
51-
if ($spatial) {
52-
if (in_array($command, ['co', 'cr', 'di', 'eq', 'in', 'ov', 'to', 'wi', 'ic', 'is', 'iv'])) {
53-
$condition = new SpatialCondition($field, $command, $parts[2]);
54-
}
55-
} else {
56-
if (in_array($command, ['cs', 'sw', 'ew', 'eq', 'lt', 'le', 'ge', 'gt', 'bt', 'in', 'is'])) {
57-
$condition = new ColumnCondition($field, $command, $parts[2]);
58-
}
53+
if ($spatial) {
54+
if (in_array($command, ['co', 'cr', 'di', 'eq', 'in', 'ov', 'to', 'wi', 'ic', 'is', 'iv'])) {
55+
$condition = new SpatialCondition($field, $command, $parts[2]);
56+
}
57+
} else {
58+
if (in_array($command, ['cs', 'sw', 'ew', 'eq', 'lt', 'le', 'ge', 'gt', 'bt', 'in', 'is'])) {
59+
$condition = new ColumnCondition($field, $command, $parts[2]);
5960
}
6061
}
6162
if ($negate) {

src/Tqdev/PhpCrudApi/Request.php

+3-15
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,10 @@ private function decodeBody(String $body) /*: ?object*/
9999

100100
private function parseBody(String $body = null) /*: void*/
101101
{
102-
if ($body) {
103-
$object = $this->decodeBody($body);
104-
} else {
105-
if (!empty($_FILES)) {
106-
$object = (object) $_POST;
107-
} else {
108-
$input = file_get_contents('php://input');
109-
$object = $this->decodeBody($input);
110-
}
102+
if (!$body) {
103+
$body = file_get_contents('php://input');
111104
}
112-
$this->body = $object;
105+
$this->body = $this->decodeBody($body);
113106
}
114107

115108
public function getMethod(): String
@@ -187,9 +180,4 @@ public static function fromString(String $request): Request
187180
}
188181
return new Request($method, $path, $query, $headers, $body);
189182
}
190-
191-
public function getUploadedFiles(): array
192-
{
193-
return $_FILES;
194-
}
195183
}

tests/functional/001_records/055_filter_category_on_null_icon.log

+8
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,11 @@ Content-Type: application/json
55
Content-Length: 94
66

77
{"records":[{"id":1,"name":"announcement","icon":null},{"id":2,"name":"article","icon":null}]}
8+
===
9+
GET /records/categories?filter=icon,is
10+
===
11+
200
12+
Content-Type: application/json
13+
Content-Length: 94
14+
15+
{"records":[{"id":1,"name":"announcement","icon":null},{"id":2,"name":"article","icon":null}]}

0 commit comments

Comments
 (0)