1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
<?php
namespace Digitigrade\Model;
use Digitigrade\Model;
use Digitigrade\StorageProvider;
class StorageObject extends Model {
public string $oid;
public string $provider;
public string $token;
public string $filename;
public string $mimetype;
public \DateTimeImmutable $created;
/**
* Creates a new storage object on the given provider by consuming a local file
* @param string $provider class name of the storage provider to use
* @param string $path path to local file (will be deleted)
* @param bool $checkIsUpload if true, ensures that the local file was uploaded via HTTP
* @return self
*/
public static function createFromFile(string $provider, string $path, string $filename, bool $checkIsUpload = false): self {
if (!is_file($path)) {
throw new \RuntimeException('local file does not exist');
}
$mimetype = mime_content_type($path);
$p = new $provider();
assert($p instanceof StorageProvider);
$token = $p->storeFile($path, $checkIsUpload);
$obj = new self();
$obj->oid = random_printable_bytes();
$obj->provider = $p::class;
$obj->token = $token;
$obj->filename = $filename;
$obj->mimetype = $mimetype;
$obj->created = new \DateTimeImmutable();
$obj->save();
return $obj;
}
public static function createFromUpload(string $provider, array $uploadInfo): self {
return self::createFromFile($provider, $uploadInfo['tmp_name'], $uploadInfo['name'], true);
}
public static function findByOid(string $oid): ?self {
return self::findWhere('oid = ?', [$oid]);
}
public static function findByProviderTokenPair(string $provider, string $token): ?self {
return self::findWhere('provider = ? AND token = ?', [$provider, $token]);
}
protected function getUpdateWhereClause(\PDO $db): ?string {
if (isset($this->oid) && self::findByOid($this->oid) != null) {
return 'oid = ' . $db->quote($this->oid);
}
if (self::findByProviderTokenPair($this->provider, $this->token) != null) {
return 'provider = ' . $db->quote($this->provider) . ' AND token = ' . $db->quote($this->token);
}
return null;
}
private function getProvider(): StorageProvider {
return new $this->provider();
}
/**
* Deletes this object from the storage backend and removes it from the database.
* @return void
*/
public function delete() {
$this->getProvider()->delete($this->token);
$this->remove();
}
/**
* Gets the entire content of this object.
* @return string
*/
public function retrieve(): string {
return $this->getProvider()->retrieve($this->token);
}
/**
* Streams the content of this object to the web client (stdout).
* @return void
*/
public function passthrough() {
$this->getProvider()->passthrough($this->token, $this->mimetype);
}
/**
* Gets a direct public URL to this object, if one exists.
* @return ?string the URL or null if none is available
*/
public function getDirectUrl(): ?string {
return $this->getProvider()->directUrl($this->token);
}
public function getUrl(bool $allowDirect = true): string {
if ($allowDirect) {
$url = $this->getDirectUrl();
if ($url != null) {
return $url;
}
}
return path_to_uri("/storage/$this->oid");
}
/**
* @return bool if this object is a supported image file
*/
public function isImage(): bool {
return in_array($this->mimetype, [
'image/apng',
'image/avif',
'image/gif',
'image/jpeg',
'image/png',
'image/svg+xml',
'image/webp',
]);
}
/**
* @return bool if this object is a supported audio file
*/
public function isAudio(): bool {
// TODO: be a bit more careful about what counts as supported
return str_starts_with($this->mimetype, 'audio/');
}
/**
* @return bool if this object is a supported video file
*/
public function isVideo(): bool {
// TODO: be a bit more careful about what counts as supported
return str_starts_with($this->mimetype, 'video/');
}
}
|