Edit via SFTP
<?php namespace ferret\users;
 
class ctClients extends cLogicTable {
 
    // ++ SETUP ++ //
 
    // CEMENT
    protected function GetTableName() : string { return 'user_client'; }
    // CEMENT
    protected function SingleRowClass() : string { return crcClient::class; }
 
    // -- SETUP -- //
    // ++ ENVIRONMENT ++ //
 
    static protected function InputCRC() : string {
        $sAddr = self::InputAddress();
        $sAgent = self::InputBrowser();
        $nCRC = crc32($sAddr.' '.$sAgent);
        $sCRC = sprintf('%u',$nCRC);	// make sure is unsigned
        return $sCRC;
    }
    static protected function InputAddress() { return \fcHTTP::ClientAddress_string(); }
    static protected function InputBrowser() { return \fcHTTP::ClientBrowser_string(); }
    static protected function InputDomain() { return gethostbyaddr(self::InputAddress()); }
 
    // -- ENVIRONMENT -- //
    // ++ RECORDS ++ //
 
    public function MakeRecord_forCRC() : \ferret\data\cRecordResult {
        $sCRC = self::InputCRC();
        $osrs = $this->SelectRecords("CRC='$sCRC'");
        $rs = $osrs->Rowset()->GetIt();
        $rs->RequireSpace();
        if ($rs->HasRows()) {
            #$rs = $osrs->GetRows();
            #$os = $rs->Space();// DEBUG TEST
            // the current browser already has a session record
            $osrc = $rs->NextRow();	// get first row (should be the only one)
        } else {
            // need to create a new session record
            $sAddr = self::InputAddress();
            $sDom = self::InputDomain();
 
            $db = $this->Database()->GetIt();            $sqlAddress = $db->SanitizeValue($sAddr);
            if ($sAddr == $sDom) {
                $sqlDomain = 'NULL';
            } else {
                $sqlDomain = $db->SanitizeValue($sDom);
            }
            $sqlBrowser = $db->SanitizeValue(self::InputBrowser());
            $ar = array(
              'CRC'		=> $db->SanitizeValue($sCRC),
              'Address'		=> $sqlAddress,
              'Domain'		=> $sqlDomain,
              'Browser'		=> $sqlBrowser,
              'WhenFirst'	=> 'NOW()'
              );
            $osNew = $this->DoInsert($ar);
            if (!$osNew->GetOkay()) {
                $e = new \ferret\except\cInternal('Could not insert new client record.');
                $e->AddDiagnostic('CLIENT RECORD TO ADD:'.fcArray::Render($ar));
                $e->AddDiagnostic('SQL: '.$osNew->GetSQL());
                throw $e;
            }
            $idNew = $osNew->GetID();
            $osrc = $this->GetRow_fromKey($idNew);
        }
        return $osrc;
    }
 
    // -- RECORDS -- //
 
}
class crcClient extends cLogicRecord {
 
    // ++ SETUP ++ //
 
    public function InitNew() {
        $sAddr = \fcHTTP::ClientAddress_string();
        $sAgent = \fcHTTP::ClientBrowser_string();
        $nCRC = crc32($sAddr.' '.$sAgent);
        $sCRC = sprintf('%u',$nCRC);	// make sure is unsigned
        $arInit = array(
          'ID'		=> NULL,
          'Address'	=> $sAddr,
          'Browser'	=> $sAgent,
          'Domain'	=> gethostbyaddr($sAddr),
          'CRC'		=> $sCRC
          );
        $this->UnloadCurrentRow();
        $this->SetFieldValues($arInit);
    }
 
    // -- SETUP -- //
    // ++ FIELD VALUES ++ //
 
    protected function AddressString()  : string { return $this->CellStatus('Address')->GetIt(); }
    protected function BrowserString()  : string { return $this->CellStatus('Browser')->GetIt(); }
    protected function DomainString()   : string { return $this->CellStatus('Domain')->GetIt(); }
    protected function CRC()            : string { return $this->CellStatus('CRC'); }
 
    // ++ FIELD VALUES ++ //
    // ++ FIELD CALCULATIONS ++ //
 
    public function IsValidNow() : bool {
        return (
          ($this->AddressString() == $_SERVER["REMOTE_ADDR"]) &&
          ($this->BrowserString() == $_SERVER["HTTP_USER_AGENT"])
          );
    }
 
    // -- FIELD CALCULATIONS -- //
    // ++ ACTIONS ++ //
 
    public function Stamp() { return $this->DoUpdate(array('WhenFinal'=>'NOW()')); }
 
    // -- ACTIONS -- //
 
}