setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); # $pdo->query("SET lc_time_names='de_DE'"); $sth = $pdo->query("SELECT valint FROM settings WHERE userid=0 AND sno=0"); $g_db_scheme_version = $sth->fetchColumn(); $user = User::GetInstance(); // There can be only one if ($g_scriptname != 'login.php') { $user->init_from_session(); $user->load_vessel(); } $action = NULL; $valid = FALSE; // Initialize message system $g_message = new Message; $g_success = new MessageSuccess; $g_warning = new MessageWarning; $g_error = new MessageError; // ========== MESSAGE FUNCTIONS =============================================== class Message { var $count = 0; var $text = array(); var $caption; var $alertclass; function __construct() { $this->caption = _('Information'); $this->alertclass = 'alert-info'; } function SetCaption($str) { $this->caption = $str; } function Add($msg) { $this->count++; $this->text[$this->count] = $msg; } function GetCount() { return $this->count; } function PrintOut() { if ($this->count > 0) { echo '\n"; } } } class MessageSuccess extends Message { function __construct() { $this->caption = _('Success'); $this->alertclass = 'alert-success'; } } class MessageWarning extends Message { function __construct() { $this->caption = _('Warning'); $this->alertclass = 'alert-warning'; } } class MessageError extends Message { function __construct() { $this->caption = _('Error'); $this->alertclass = 'alert-danger'; } } // ========== USER FUNCTIONS ================================================== class User { private static $instance = NULL; private $loggedin; private $errormessage; public $id; public $login; public $displayname; public $role; public $flags; public $vid; // current selected vessel public $vessel; // name of current vessel private function __construct() { $this->loggedin = FALSE; $this->errormessage = NULL; $this->flags = []; $this->vid = 1; $this->vessel = 'Yacht'; } public static function getInstance() { if (self::$instance == NULL) { self::$instance = new User(); } return self::$instance; } function login($user_name, $user_pass) { global $pdo; if ($user_name == '' or $user_pass == '') { $this->loggedin = FALSE; $this->errormessage = _('Username or password was empty'); return FALSE; } $sql = "SELECT userid, pass, displayname, role, flags FROM user WHERE login=?"; $sth = $pdo->prepare($sql); $sth->execute([$user_name]); $row = $sth->fetch(PDO::FETCH_OBJ); $this->role = $row->role; $this->flags = array_filter(explode(',', $row->flags)); if ($row->flags != 0 ) { // deleted or locked, intentionally not return detailed reason $this->errormessage = _('User account does not exist'); } elseif (password_verify($user_pass, $row->pass)) { // password check successful $_SESSION['userid'] = $row->userid; $this->loggedin = TRUE; header_location($_SESSION['prelogin'] ?? 'index.php'); } else { $this->errormessage = _('Username or password invalid'); } return FALSE; } function logout() { global $pdo; // remove session completely $_SESSION = array(); if (ini_get("session.use_cookies")) { $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] ); } session_destroy(); } function init_from_session() { global $pdo; if (!isset($_SESSION['userid'])) { $this->loggedin = FALSE; $this->errormessage = _('User not logged in'); $this->id = NULL; return; } $this->id = $_SESSION['userid']; $sql = "SELECT displayname, role FROM user WHERE userid=?"; $sth = $pdo->prepare($sql); $sth->execute([$this->id]); $row = $sth->fetch(); $this->displayname = $row['displayname']; $this->role = $row['role']; //$this->displayname = $sth->fetchColumn(); } function load_vessel() { global $pdo; $sql = "SELECT v.vid, v.vesselname " . "FROM settings AS s INNER JOIN vessel AS v ON s.valint=v.vid " . "WHERE s.userid=? and s.sno=1"; $sth = $pdo->prepare($sql); $sth->execute([$this->id]); $row = $sth->fetch(); $this->vid = $row['vid']; $this->vessel = $row['vesselname']; } function get_last_error() { return $this->errormessage; } } function get_userlist() { // Get list of all users for fast name lookup global $pdo; $ulist = array(-1 => ['-', 0]); // unknown $sql = "SELECT userid, displayname, role, flags FROM user ORDER BY displayname"; $sth = $pdo->query($sql); $res = $sth->fetchAll(); foreach ($res as $row) { $flags = array_filter(explode(',', $row['flags'])); $deleted = in_array('deleted', $flags); $locked = in_array('locked', $flags); $ulist[$row['userid']] = [$row['displayname'], $deleted, $locked]; } return $ulist; } // ========== DATABASE FUNCTIONS ============================================== function db_exec_insert($table, $params) { // $params must have keys corresponding to table fields prefixed with ':' // e.g. $param[':field'] global $pdo; global $g_error; $keys = array_keys($params); $fields = join(',', array_map(function($s) { return ltrim($s, ':'); }, $keys)); $pnames = join(',', $keys); $sql = "INSERT INTO $table ($fields) VALUES ($pnames)"; // $sth = $pdo->prepare("INSERT INTO $table ($fields) VALUES ($pnames)"); $sth = $pdo->prepare($sql); try { $sth->execute($params); } catch (PDOexception $e) { $g_error->Add('SQL-Error: '. $e->getMessage()); $g_error->Add($sql); $g_error->Add(print_r($params, true)); } return $pdo->LastInsertId(); } function db_exec_update($table, $params, $pk) { // TODO primary key with multiple fields: $pk is an array global $pdo; global $g_error; $fields = join(',', array_map(function($s) { return ltrim($s, ':') . '=' . $s; }, array_keys($params))); $sql = "UPDATE $table SET $fields WHERE $pk=:$pk"; $sth = $pdo->prepare($sql); try { $sth->execute($params); } catch (PDOexception $e) { $g_error->Add('SQL-Error: '. $e->getMessage()); $g_error->Add($sql); $g_error->Add(print_r($params, true)); return false; } return true; } function db_save_filter($flt, $sno) { global $user; global $pdo; global $g_warning; $sql = "UPDATE settings SET valstr=? WHERE userid=? AND sno=?"; $sth = $pdo->prepare($sql); try { $sth->execute([json_encode($flt), $user->id, $sno]); } catch (PDOexception $e) { $g_warning->Add('SQL-Error: '. $e->getMessage()); $g_warning->Add($sql); $g_warning->Add(print_r($flt, true)); $g_warning->Add('Setting: ', $sno); return false; } return true; } function get_enum($enum) { // Translate and beautify enums $lookup = array( 'bad' => _('Bad'), 'box' => _('Box'), 'cat' => _('Catamaran'), 'closed' => _('Closed'), 'defect' => _('Defect'), 'done' => _('Done'), 'drawing' => _('Drawing'), 'equipment' => _('Equipment'), 'estimated' => _('Estimated'), 'finished' => _('Finished'), 'fixed' => _('Fixed'), 'generic' => _('Generic'), 'good' => _('Good'), 'invoice' => _('Invoice'), 'locked' => _('Locked'), 'manual' => _('Manual'), 'mono' => _('Monohull'), 'new' => _('New'), 'normal' => _('Normal'), 'ongoing' => _('Ongoing'), 'open' => _('Open'), 'picture' => _('Picture'), 'planned' => _('Planned'), 'precise' => _('Precise'), 'repairable' => _('Repairable'), 'rough' => _('Rough'), 'storage' => _('Storage'), 'task' => _('Task'), 'tri' => _('Trimaran'), 'unknown' => _('Unknown'), 'vessel' => _('Vessel'), ); return $lookup[$enum] ?? $enum; } function db_load_enum($table, $column, $lookup=false, $as_dict=false) { // returns array of enum-values as defined in database // if lookup is true the name lookup and translaton is applied // if as_dict is true the enum value is returned as the array key global $pdo; $sql = "SELECT TRIM(TRAILING ')' FROM SUBSTRING(column_type,6)) " . "FROM information_schema.columns " . "WHERE table_name=? AND column_name=?"; $sth = $pdo->prepare($sql); $sth->execute([$table, $column]); // for PHP < 7.4 // return array_map(function($x) { return trim($x, "'"); }, explode(',', $sth->fetchColumn())); // for PHP => 7.4 $arr = array_map(fn($x) => trim($x, "'"), explode(',', $sth->fetchColumn())); if ($lookup) { if ($as_dict) { $dict = array(); foreach ($arr as $x) { $dict[$x] = get_enum($x); } return $dict; } else { return array_map(fn($x) => get_enum($x), $arr); } } else { return $arr; } } function db_get_ddtext($ddid, $ddval) { // returns single value for dropdown global $pdo; global $g_error; $sql = "SELECT ddtext FROM dropdown WHERE ddid=? AND ddval=?"; $sth = $pdo->prepare($sql); try { $sth->execute([$ddid, $ddval]); } catch(PDOException $e) { $g_error->Add($e->getMessage()); return '#err'; } return $sth->fetchColumn(); } function db_get_options($ddid, $orderby = '', $default = NULL) { // returns list for dropdown global $pdo; $list = array(); if ($default != NULL) { $list[0] = $default; } $sql = "SELECT ddval, ddtext FROM dropdown WHERE ddid=?"; if ($orderby == 'ddtext') { $sql .= ' ORDER BY ddtext'; } elseif ($orderby == 'sort') { $sql .= ' ORDER BY sort'; } else { $sql .= ' ORDER BY ddval'; } $sth = $pdo->prepare($sql); $sth->execute([$ddid]); foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) { $list[$rec[0]] = $rec[1]; } return $list; } function db_get_opt_vessel() { global $pdo; $list = array(); $sth = $pdo->query("SELECT vid, vesselname, model FROM vessel ORDER BY vid"); foreach ($sth->fetchAll(PDO::FETCH_NUM) as $row) { $list[$rec[0]] = $rec[1]; } return $list; } // Functions to get option lists (key/value) function db_get_opt_storage($vid) { global $pdo; global $g_error; $list = array(); $sql = "SELECT sid, sname FROM storage WHERE vid=? ORDER BY sname"; $sth = $pdo->prepare($sql); try { $sth->execute([$vid]); } catch(PDOException $e) { $g_error->Add($e->getMessage()); } foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) { $list[$rec[0]] = $rec[1]; } return $list; } function db_get_opt_box($vid) { global $pdo; global $g_error; $list = array(); $sql = "SELECT boxid, label, content " . "FROM box INNER JOIN storage USING (sid) " . "WHERE vid=? " . "ORDER BY label"; $sth = $pdo->prepare($sql); try { $sth->execute([$vid]); } catch(PDOException $e) { $g_error->Add($e->getMessage()); } foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) { $list[$rec[0]] = $rec[1] . ' - '. $rec[2]; } return $list; } function db_get_opt_equip($vid, $default=NULL) { global $pdo; global $g_error; if (isset($default)) { $list = $default; } else { $list = array(); } $sql = "SELECT eid, ename FROM equipment WHERE vid=? ORDER BY ename"; $sth = $pdo->prepare($sql); try { $sth->execute([$vid]); } catch(PDOException $e) { $g_error->Add($e->getMessage()); } foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) { $list[$rec[0]] = $rec[1]; } return $list; } function db_get_opt_manuf($default=NULL) { global $pdo; if (isset($default)) { $list = $default; } else { $list = array(); } $sql = "SELECT compid, compname FROM company WHERE comptype=2 ORDER BY compname"; $sth = $pdo->query($sql); foreach ($sth->fetchAll(PDO::FETCH_NUM) as $row) { $list[$row[0]] = $row[1]; } return $list; } function db_get_opt_supp($default=NULL) { global $pdo; if (isset($default)) { $list = $default; } else { $list = array(); } $sql = "SELECT compid, compname FROM company WHERE comptype=1 ORDER BY compname"; $sth = $pdo->query($sql); foreach ($sth->fetchAll(PDO::FETCH_NUM) as $row) { $list[$row[0]] = $row[1]; } return $list; } function db_get_opt_proj($vid, $default=NULL) { global $pdo; global $g_error; if (isset($default)) { $list = $default; } else { $list = array(); } $sql = "SELECT projid, projname FROM project WHERE vid=? ORDER BY projname"; $sth = $pdo->prepare($sql); try { $sth->execute([$vid]); } catch(PDOException $e) { $g_error->Add($e->getMessage()); } foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) { $list[$rec[0]] = $rec[1]; } return $list; } function db_get_filter($user, $sno) { global $pdo; global $g_warning; $flt = new stdClass(); $sth = $pdo->prepare("SELECT valstr FROM settings WHERE userid=? AND sno=?"); try { $sth->execute([$user, $sno]); $json = $sth->fetchColumn(); if (!$json) { // no settings record. create empty one for later updates $sth = $pdo->prepare("INSERT INTO settings (userid, sno, valstr) VALUES (?, ?, '{}')"); $sth->execute([$user, $sno]); } else { $flt = json_decode($json); } } catch (PDOexception $e) { $g_warning->Add('SQL-Error: '. $e->getMessage()); } return $flt; } function date_to_sql($var) { if (!isset($var) || $var == '') { return NULL; } else { list($d, $m, $y) = explode('.', $var); return sprintf("%04d-%02d-%02d", $y, $m, $d); } } function float_to_sql($var) { global $g_lconv; if (!isset($var) || $var == '') { return NULL; } else { // remove thousands separator $var = str_replace($g_lconv['thousands_sep'], '', $var); // force decimal point if ($g_lconv['decimal_point'] != '.') { $var = str_replace($g_lconv['decimal_point'], '.', $var); } return $var; } } // ========== FORM FUNCTIONS ================================================== function form_create_select($fieldname, $label, $optlist, $selval=NULL) { echo '
', "\n"; echo '\n"; echo '\n"; echo "
\n"; } function form_action_buttons($script, $id) { echo ""; echo '', "\n"; echo '', "\n"; echo "\n"; } function form_add_button($script, $id=NULL, $idname='id') { echo '
', "\n"; echo '', _('Add'), "\n"; echo "
\n"; } function form_view_buttons($script, $id) { echo '
', "\n"; echo '', _('Edit'), "\n"; echo ' '; echo '', _('Delete'), "\n"; echo ' '; echo '', _('Back'), "\n"; echo "
\n"; } function form_new_buttons($script) { echo '
', "\n"; echo '\n"; echo '', _('Back'), "\n"; echo "
\n"; } function form_edit_buttons($script, $id) { echo '
', "\n"; echo '\n"; echo '', _('Back'), "\n"; echo "
\n"; } function form_delete_buttons($script, $id, $token) { echo '
', "\n"; echo '
', "\n"; echo '', "\n"; echo '', "\n"; echo '\n"; echo '', _('Back'), "\n"; echo "
\n"; echo "\n"; } // ========== COMMON FUNCTIONS ================================================ function header_location($location) { header("Location: $location"); exit; } function form_get_action() { if (!isset($_POST['submit'])) { if (isset($_GET['f'])) { $submit = $_GET['f']; // strip parameters /* $pos = strpos($submit, '?'); if ($pos > 2) { $submit = substr($submit, 0, $pos); } */ } else { $submit = NULL; } } else { $submit = $_POST['submit']; } if (is_array($submit)) { $submit = key($submit); } return strtolower($submit); } function get_color_brightness($color) { // returns a value between 0 and 1 // color is a 6 char hex string list($red, $green, $blue) = array_map('hexdec', str_split($color, 2)); $red = $red / 255 * 0.2126; $green = $green / 255 * 0.7152; $blue = $blue / 255 * 0.0722; return $red + $green + $blue; } function gpc_get_string(&$GPC, $varname, $maxlen = NULL, $default = NULL) { if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) { return $default; } $s = trim($GPC[$varname]); if (isset($maxlen)) { return substr($s, 0, $maxlen); } return $s; } function gpc_get_int(&$GPC, $varname, $default = NULL) { if (!isset($GPC[$varname])) { return $default; } return (int)$GPC[$varname]; } function gpc_get_float(&$GPC, $varname, $default = NULL) { global $g_lconv; if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) { return $default; } $var = str_replace($g_lconv['thousands_sep'], '', $GPC[$varname]); if ($g_lconv['decimal_point'] != '.') { $var = str_replace($g_lconv['decimal_point'], '.', $var); } return (double)$var; } function gpc_get_currency(&$GPC, $varname, $default = NULL) { global $g_lconv; if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) { return $default; } $var = str_replace($g_lconv['thousands_sep'], '', $GPC[$varname]); if ($g_lconv['decimal_point'] != '.') { $var = str_replace($g_lconv['decimal_point'], '.', $var); } return (double)$var; } function gpc_get_bool(&$GPC, $varname, $default = FALSE) { if (!isset($GPC[$varname])) { return $default; } $gpcvar = trim($GPC[$varname]); if (strcasecmp('off', $gpcvar) == 0 || strcasecmp('no', $gpcvar) == 0 || strcasecmp('false', $gpcvar) == 0 || strcasecmp('no', $gpcvar) == 0 || strcasecmp('0', $gpcvar) == 0 || strcasecmp('nein', $gpcvar) == 0) { return FALSE; } return TRUE; } function gpc_get_date(&$GPC, $varname, $default = NULL) { if (!isset($GPC[$varname]) || $GPC[$varname] == '') { return $default; } return $GPC[$varname]; } function gpc_get_color(&$GPC, $varname, $default = NULL) { if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) { return $default; } $color = $GPC[$varname]; if ((strlen($color) == 7) and (substr($color, 0, 1) == '#')) { $color = substr($color, 1); } if ((strlen($color) != 6) or (! ctype_xdigit($color))) { return $default; } return strtoupper($color); } function format_float($val, $decimals = 2, $suffix = '') { global $g_lconv; if (!isset($val) || $val == '') { return ''; } return number_format($val, $decimals, $g_lconv['decimal_point'], $g_lconv['thousands_sep']) . ($suffix ? " $suffix" : ''); } function format_currency($val) { global $g_lconv; if (!isset($val) || $val == '') { return ''; } if ($g_lconv['currency_symbol'] == '$') { return '$'.number_format($val, 2, $g_lconv['decimal_point'], $g_lconv['thousands_sep']); } else { return number_format($val, 2, $g_lconv['decimal_point'], $g_lconv['thousands_sep']) . ' ' . $g_lconv['currency_symbol']; } } function format_color($color) { $colstr = '#' . $color . '' ; return $colstr; } function format_filesize($size, $format=2) { switch ($format) { case 1: // short if ($size < 1024) { $size_string = sprintf(_('%d B'), $size); } elseif ($size < 1048576) { $size_string = sprintf(_('%.1f kB'), $size/1024); } else { $size_string = sprintf(_('%.1f MB'), $size/1048576); } break; case 2: // medium if ($size < 1024) { $size_string = sprintf(_('%d Byte'), $size); } elseif ($size < 1048576) { $size_string = sprintf(_('%.1f kByte'), $size/1024); } else { $size_string = sprintf(_('%.1f MByte'), $size/1048576); } break; case 3: // long if ($size < 1024) { $size_string = sprintf(_('%d Byte'), $size); } elseif ($size < 1048576) { $size_string = sprintf(_('approx. %.1f kByte'), $size/1024); } else { $size_string = sprintf(_('approx. %.1f MByte'), $size/1048576); } break; default: $size_string = trim($size); } return $size_string; } function get_pagination($script, $page, $lastpage) { // no direct output, returns string for multiple output if ($lastpage < 2) { return ''; } $out = '\n"; return $out; } function pdf_get_pagecount($filename) { $pages = exec("/usr/bin/mutool show $filename Root/Pages/Count", $output, $retval); // TODO error checking return $pages; } function pdf_get_preview($docid) { global $g_doc_basepath; // create file in thumbs if needed $thumbfile = $g_doc_basepath . '/thumbs/doc-' . $docid . '.jpg'; if (file_exists($thumbfile)) { //return " [_('Equipment')], 'inventory.php' => [_('Inventory')], 'provisions.php' => [_('Provisions')], 'maintenance.php' => [_('Maintenance')], 'projects.php' => [_('Projects')], 'documents.php' => [_('Documents')], 'manual.php' => [''], 'logout.php' => [''] );