db = $db; } /** * Erstellt einen neuen Token für ein Dolibarr-Objekt. * Räumt dabei abgelaufene Tokens gleich mit auf (kein Cronjob nötig). * @param int $fk_element ID des Dolibarr-Objekts (z.B. Auftrags-ID) * @param string $element_type Typ: 'order', 'invoice', 'propal' * @param int $fk_user User-ID * @param int $lifetime Gültigkeit in Sekunden (Standard: 3600) * @param int $max_uploads Max. Uploads (Standard: 100) * @return string|false Hex-Token bei Erfolg */ public function create($fk_element, $element_type, $fk_user, $lifetime = null, $max_uploads = null) { // Opportunistisches Cleanup: entferne abgelaufene Tokens bei jedem Insert $this->db->query("DELETE FROM ".$this->db->prefix()."bericht_upload_token" ." WHERE expires_at < '".$this->db->idate(dol_now())."'", 1); $this->token = bin2hex(random_bytes(32)); $this->fk_element = (int) $fk_element; $this->element_type = $element_type; $this->fk_user_creat = (int) $fk_user; $this->datec = dol_now(); $this->expires_at = $this->datec + ($lifetime ?: self::DEFAULT_LIFETIME); $this->max_uploads = $max_uploads ?: self::DEFAULT_MAX_UPLOADS; $this->uploads_count = 0; $sql = "INSERT INTO ".$this->db->prefix()."bericht_upload_token " ."(token, fk_element, element_type, fk_user_creat, expires_at, uploads_count, max_uploads, datec) VALUES (" ."'".$this->db->escape($this->token)."'," .$this->fk_element."," ."'".$this->db->escape($this->element_type)."'," .$this->fk_user_creat."," ."'".$this->db->idate($this->expires_at)."'," ."0," .$this->max_uploads."," ."'".$this->db->idate($this->datec)."'" .")"; if (!$this->db->query($sql)) return false; $this->id = $this->db->last_insert_id($this->db->prefix()."bericht_upload_token"); return $this->token; } /** * Lädt einen Token und prüft Gültigkeit. * @return BerichtUploadToken|null */ public static function fetchValid(DoliDB $db, $token) { if (!preg_match('/^[a-f0-9]{64}$/', $token)) return null; $sql = "SELECT rowid, token, fk_element, element_type, fk_user_creat, expires_at, uploads_count, max_uploads, datec" ." FROM ".$db->prefix()."bericht_upload_token" ." WHERE token = '".$db->escape($token)."'" ." AND expires_at > '".$db->idate(dol_now())."'" ." AND uploads_count < max_uploads"; $res = $db->query($sql); if (!$res || $db->num_rows($res) === 0) return null; $obj = $db->fetch_object($res); $t = new self($db); $t->id = (int) $obj->rowid; $t->token = $obj->token; $t->fk_element = (int) $obj->fk_element; $t->element_type = $obj->element_type; $t->fk_user_creat = (int) $obj->fk_user_creat; $t->expires_at = $db->jdate($obj->expires_at); $t->uploads_count = (int) $obj->uploads_count; $t->max_uploads = (int) $obj->max_uploads; $t->datec = $db->jdate($obj->datec); return $t; } /** * Ermittelt den Upload-Ordner für dieses Token basierend auf element_type. * @return string|false Absoluter Pfad zum Upload-Ordner, false bei Fehler */ public function getUploadDir() { global $conf; $parent = $this->fetchParentObject(); if (!$parent) return false; $ref = dol_sanitizeFileName($parent->ref); switch ($this->element_type) { case 'order': return $conf->commande->multidir_output[$parent->entity].'/'.$ref; case 'invoice': return $conf->facture->multidir_output[$parent->entity].'/'.$ref; case 'propal': return $conf->propal->multidir_output[$parent->entity].'/'.$ref; default: return false; } } /** * Lädt das Dolibarr-Parent-Objekt (Auftrag/Rechnung/Angebot). * @return CommonObject|false */ public function fetchParentObject() { switch ($this->element_type) { case 'order': require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; $obj = new Commande($this->db); break; case 'invoice': require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; $obj = new Facture($this->db); break; case 'propal': require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; $obj = new Propal($this->db); break; default: return false; } if ($obj->fetch($this->fk_element) <= 0) return false; return $obj; } public function incrementCount() { $this->uploads_count++; return $this->db->query("UPDATE ".$this->db->prefix()."bericht_upload_token" ." SET uploads_count = uploads_count + 1" ." WHERE rowid = ".((int) $this->id)); } /** * Instanz-Methode für den Dolibarr-Cronjob. * Räumt expired Tokens auf. * * @return int Anzahl gelöschter Tokens (>=0), -1 bei Fehler */ public function cleanupExpired() { $sql = "DELETE FROM ".$this->db->prefix()."bericht_upload_token" ." WHERE expires_at < '".$this->db->idate(dol_now())."'"; $res = $this->db->query($sql); if (!$res) { $this->error = $this->db->lasterror(); return -1; } return $this->db->affected_rows($res); } /** * Statische Variante für Direktaufrufe außerhalb des Cronjobs. */ public static function cleanupExpiredStatic(DoliDB $db) { $db->query("DELETE FROM ".$db->prefix()."bericht_upload_token" ." WHERE expires_at < '".$db->idate(dol_now())."'"); } }