chimera-mark2-core-release/core/fox/file.php

269 lines
7.6 KiB
PHP

<?php namespace fox;
use fox\meta\settings;
use stdClass;
/**
*
* Class fox\file
*
* @copyright MX STAR LLC 2018-2022
* @version 4.0.0
* @author Pavel Dmitriev
* @license GPLv3
*
**/
class file extends baseClass implements externalCallable {
protected $id;
public $uuid;
public $fileName;
public $module;
public $class;
public $refId;
public $public=false;
public $private=false;
public $ownerId=null;
public time $uploadStamp;
public time $expireStamp;
protected $__data;
public static $sqlTable="tblFiles";
public static $allowDeleteFromDB = true;
# file access token expires in 120 seconds
const fileTokenTTL=120;
const defaultBucket="files";
protected function __xConstruct() {
$this->expireStamp=new time();
$this->uploadStamp=time::current();
}
public static $sqlColumns = [
"uuid" => [
"type" => "CHAR(36)",
"index"=>"UNIQUE",
],
"fileName" => [
"type" => "VARCHAR(255)",
],
"module" => [
"type" => "VARCHAR(255)",
"index" => "INDEX"
],
"class" => [
"type" => "VARCHAR(255)",
"index" => "INDEX"
],
"refId" => [
"type" => "VARCHAR(255)",
],
"ownerId" => [
"type" => "INT",
"index" => "INDEX",
"nullable"=>true
],
"expireStamp" => [
"type" => "DATETIME",
"index" => "INDEX",
"nullable"=>true
],
"uploadStamp" => [
"type" => "DATETIME",
"index" => "INDEX",
"nullable"=>true,
],
];
protected function validateDelete()
{
if (empty($this->id)) { throw new foxException("Unable to delete empty file"); }
if ($this->uuid) {
$s3=new s3client();
$s3->deleteObject(static::defaultBucket, $this->uuid);
}
return true;
}
protected function validateSave()
{
if (empty($this->uuid)) { $this->uuid = common::getUUID(); }
return true;
}
protected static function xSearch($where, $pattern, ?array $options, sql $sql) {
$xWhere="";
if (!empty($options["uuid"])) {
$xWhere .= ($xWhere?" AND ":"")." `uuid` = '".common::clearInput($options["uuid"],"0-9a-z-")."'";
}
if (!empty($options["instance"])) {
$xWhere .= ($xWhere?" AND ":"")." `module` = '".common::clearInput($options["instance"])."'";
}
if (!empty($options["class"])) {
$xWhere .= ($xWhere?" AND ":"")." `class` = '".common::clearInput($options["class"],'0-9A-Za-z_\.\-\\\/')."'";
}
if (!empty($options["refId"])) {
$xWhere .= ($xWhere?" AND ":"")." `refId` = '".common::clearInput($options["refId"])."'";
}
if (!empty($options["expired"])) {
$xWhere .= ($xWhere?" AND ":"")." `expireStamp` <= '".time::current()."'";
}
if ($xWhere) {
if ($where) {
$where = "(".$where.") AND (".$xWhere.")";
} else {
$where = $xWhere;
}
}
return ["where"=>$where, "join"=>null];
}
protected static function prepareFileUpload($fileName, object $ref, string $instance=null, user $owner=null, $ttl=null) {
$f=new static();
$f->fileName=$fileName;
$f->module=$instance;
if ($owner) { $f->ownerId=$owner->id; }
if ($ttl) { $f->expireStamp=time::current()->addSec($ttl); }
$f->class = $ref::class;
$f->uuid=common::getUUID();
return $f;
}
public function upload($data) {
if (!empty($this->id)) {
throw new foxException("Not allowed for existing files");
}
if (empty($this->uuid)) {
throw new foxException("Empty UUID not allowed here");
}
$s3=new s3client();
if (!$s3->headBucket(static::defaultBucket)) {
$s3->createBucket(static::defaultBucket);
}
$s3->putObject(static::defaultBucket,$this->uuid, $data);
$this->save();
}
public static function directUpload($data, $fileName, object $ref, string $instance=null, user $owner=null, $ttl=null) {
$f=static::prepareFileUpload($fileName, $ref, $instance, $owner, $ttl);
$f->upload($data);
return $f;
}
public static function getByUUID(string $uuid) : file {
$files = file::search(options: ["uuid"=>$uuid]);
if ($files->result) {
return array_shift($files->result);
} else {
throw new foxException("File not found", 404);
}
}
public function getContent() {
if ($this->uuid) {
$s3=new s3client();
return $s3->getObject(static::defaultBucket, $this->uuid);
}
}
public function getDownloadToken() {
if (empty($this->id)) {
throw new foxException("Empty fileId not allowed here");
};
$token=common::genPasswd(32);
$c=new cache();
$c->set('fileDnldToken-'.$token,$this,static::fileTokenTTL);
return $token;
}
public static function getByToken($token, $upload=false) {
$c=new cache();
$prefix=$upload?"fileUpldToken":"fileDnldToken";
$ftile=$c->get($prefix.'-'.$token,true);
if ($ftile) {
$file = new static($ftile);
$c->del($prefix.'-'.$token);
return $file;
} else {
throw new foxException("Invalid token",404);
}
}
public static function getUploadToken($fileName, object $ref, string $instance=null, user $owner=null) {
$f=static::prepareFileUpload($fileName, $ref, $instance, $owner);
$token=common::genPasswd(32);
$c=new cache();
$c->set('fileUpldToken-'.$token,$f,static::fileTokenTTL);
return $token;
}
#### REST API
public static function API_UnAuth_GET(request $request) {
if (!empty($request->parameters)) throw new foxException("Invalid request", 400);
$file2=file::getByToken($request->function);
header_remove('Content-Type');
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$file2->fileName);
print($file2->getContent());
exit;
}
public static function API_UnAuth_POST(request $request) {
if (!empty($request->parameters)) throw new foxException("Invalid request", 400);
$err=false;
$rv=[];
foreach ($_FILES as $sFile) {
$sOK=$sFile["error"]==0;
if (!$sOK) {
throw new foxException("File upload error");
}
}
foreach ($_FILES as $token=>$sFile) {
$sOK=$sFile["error"]==0;
if ($sOK) {
$file = file::getByToken(common::clearInput($token),true);
$tmpPath=$sFile["tmp_name"];
$data=file_get_contents($tmpPath);
$file->upload($data);
$rv[$token]=[
"fileName"=>$sFile["name"],
"fileSize"=>$sFile["size"],
"status"=>"OK",
];
} else {
$err=true;
$rv[$token]=[
"fileName"=>$sFile["name"],
"status"=>"Fail",
];
}
}
return [
"status"=>$err?"ERR":"OK",
"details"=>$rv,
];
}
}
?>