Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
FinishUploadEndpoint
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
72
0.00% covered (danger)
0.00%
0 / 1
 handle
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2
3namespace Olz\Api\Endpoints;
4
5use Olz\Api\OlzTypedEndpoint;
6
7/**
8 * @extends OlzTypedEndpoint<
9 *   array{
10 *     id: non-empty-string,
11 *     numberOfParts: int<1, 1000>,
12 *   },
13 *   array{
14 *     status: 'OK'|'ERROR',
15 *   }
16 * >
17 */
18class FinishUploadEndpoint extends OlzTypedEndpoint {
19    protected function handle(mixed $input): mixed {
20        $this->checkPermission('any');
21
22        $data_path = $this->envUtils()->getDataPath();
23        $upload_id = $input['id'];
24        $upload_path = "{$data_path}temp/{$upload_id}";
25        if (!is_file($upload_path)) {
26            $this->log()->error("Could not finish upload. Invalid ID: '{$upload_id}'.");
27            return ['status' => 'ERROR'];
28        }
29
30        $num_parts = $input['numberOfParts'];
31        $first_part_path = "{$upload_path}_0";
32        if (!is_file($first_part_path)) {
33            $this->log()->error("Upload with ID {$upload_id} is missing the first part.");
34            return ['status' => 'ERROR'];
35        }
36        $first_content = file_get_contents($first_part_path) ?: '';
37        @unlink($first_part_path);
38        $res = preg_match("/^data\\:([^\\;]*)\\;base64\\,(.+)$/", $first_content, $matches);
39        if (!$res) {
40            $this->log()->error("Upload with ID {$upload_id} does not have base64 header.");
41            return ['status' => 'ERROR'];
42        }
43        $mime_type = $matches[1];
44        $base64 = $matches[2];
45        $missing_parts = [];
46        for ($part = 1; $part < $num_parts; $part++) {
47            $part_path = "{$upload_path}_{$part}";
48            if (!is_file($part_path)) {
49                $missing_parts[] = $part;
50                continue;
51            }
52            $part_content = file_get_contents($part_path);
53            $base64 .= $part_content;
54            @unlink($part_path);
55        }
56        if (count($missing_parts) > 0) {
57            $pretty_missing_parts = implode(', ', $missing_parts);
58            $this->log()->error("Upload with ID {$upload_id} is missing parts {$pretty_missing_parts}.");
59            return ['status' => 'ERROR'];
60        }
61        $binary_data = base64_decode(str_replace(" ", "+", $base64));
62
63        file_put_contents($upload_path, $binary_data);
64
65        return ['status' => 'OK'];
66    }
67}