,
*/
/**
* Datenverbund Services
* Anbindung für Datenverbund des Bundesrechenzetrums zur
* Abfrage und Vergabe von Matrikelnummern
*/
require_once(dirname(__FILE__).'/basis_db.class.php');
require_once(dirname(__FILE__).'/person.class.php');
require_once(dirname(__FILE__).'/student.class.php');
require_once(dirname(__FILE__).'/studiensemester.class.php');
require_once(dirname(__FILE__).'/adresse.class.php');
require_once(dirname(__FILE__).'/webservicelog.class.php');
class dvb extends basis_db
{
const DVB_URL_WEBSERVICE_OAUTH = 'https://stubei-q.portal.at/dvb/oauth/token';
const DVB_URL_WEBSERVICE_SVNR = 'https://stubei-q.portal.at/rws/0.1/simpleStudentBySozialVersicherungsnummer.xml';
const DVB_URL_WEBSERVICE_ERSATZKZ = 'https://stubei-q.portal.at/rws/0.1/simpleStudentByErsatzKennzeichen.xml';
const DVB_URL_WEBSERVICE_RESERVIERUNG = 'https://stubei-q.portal.at/dvb/matrikelnummern/1.0/reservierung.xml';
const DVB_URL_WEBSERVICE_MELDUNG = 'https://stubei-q.portal.at/dvb/matrikelnummern/1.0/meldung.xml';
public $authentication;
private $username;
private $password;
protected $debug;
public $debug_output = '';
/**
* Constructor
* @param string $username Username fuer OAuth2 Login.
* @param string $password Passwort fuer OAuth2 Login.
* @param bool $debug Enables/Disables Debugging.
*/
public function __construct($username, $password, $debug = false)
{
$this->username = $username;
$this->password = $password;
$this->debug = $debug;
}
/**
* Versucht die Matrikelnummer für eine Person zu ermitteln.
* Wenn die Person noch keine Matrikelnummer besitzt, wird eine neue Matrikelnummer
* angefordert und der Person zugeordnet
* @param int $person_id ID der Person.
* @return boolean true wenn Erfolgreich, false im Fehlerfall
*/
public function assignMatrikelnummer($person_id)
{
$person = new person();
if (!$person->load($person_id))
{
$this->errormsg = $person->errormsg;
return false;
}
if ($person->svnr != '')
{
$matrikelnummer = $this->getMatrikelnrBySVNR($person->svnr);
if ($matrikelnummer === false && $this->errormsg != '')
{
$this->logRequest($person, 'getMatrikelnrBySVNR', false);
return false;
}
}
elseif ($person->ersatzkennzeichen != '')
{
$matrikelnummer = $this->getMatrikelnrByErsatzkennzeichen($person->ersatzkennzeichen);
if ($matrikelnummer === false && $this->errormsg != '')
{
$this->logRequest($person, 'getMatrikelnrByErsatzkennzeichen', false);
return false;
}
}
else
{
$this->errormsg = 'Person braucht SVNR oder Ersatzkennzeichen';
return false;
}
if ($matrikelnummer !== false && $matrikelnummer != '')
{
// Matrikelnummer wurde gefunden
// Bei Person speichern
$person->matr_nr = $matrikelnummer;
if ($person->save())
{
$this->logRequest($person, 'assignExistingMatrikelnummer', true, $matrikelnummer);
return true;
}
}
else
{
// Es wurde noch keine Matrikelnummer zu dieser Person zugeordnet
// Es wird eine neue Matrikelnummer aus dem Kontingent angefordert
// und an die Person vergeben
// Studienjahr ermitteln
$qry = "
SELECT
studiensemester_kurzbz, prestudent_id
FROM
public.tbl_student
JOIN public.tbl_prestudent USING(prestudent_id)
JOIN public.tbl_prestudentstatus USING(prestudent_id)
JOIN public.tbl_benutzer ON(tbl_student.student_uid = tbl_benutzer.uid)
WHERE
tbl_prestudent.person_id=".$this->db_add_param($person->person_id)."
AND tbl_benutzer.aktiv
AND tbl_prestudentstatus.status_kurzbz='Student'
AND tbl_prestudent.bismelden
ORDER BY tbl_prestudentstatus.datum desc LIMIT 1
";
$prestudent_id = '';
$studiensemester_kurzbz = '';
if ($result = $this->db_query($qry))
{
if ($row = $this->db_fetch_object($result))
{
$studiensemester_kurzbz = $row->studiensemester_kurzbz;
$prestudent_id = $row->prestudent_id;
}
else
{
$this->logRequest($person, 'assignNewMatrikelnummer', false);
$this->errormsg = 'Fehler beim Ermitteln des Studienjahrs für diese Person';
return false;
}
}
else
{
$this->logRequest($person, 'assignNewMatrikelnummer', false);
$this->errormsg = 'Fehler beim Ermitteln des Studienjahrs für diese Person';
return false;
}
$studienjahr = substr($studiensemester_kurzbz, 4);
$art = substr($studiensemester_kurzbz, 0, 2);
if ($art == 'SS')
$studienjahr = $studienjahr - 1;
// Erstaustattung im Jahr 2018. Alle davor bekommen 18er Nummern
if ($studienjahr < 2018)
$studienjahr = 2018;
// Neue Matrikelnummer aus Kontingent anfordern
$kontingent = $this->getKontingent(DVB_BILDUNGSEINRICHTUNG_CODE, $studienjahr);
if ($kontingent !== false && isset($kontingent[0]))
{
$person_meldung = new stdClass();
$person_meldung->matrikelnummer = $kontingent[0];
$person_meldung->vorname = $person->vorname;
$person_meldung->nachname = $person->nachname;
$person_meldung->geburtsdatum = $person->gebdatum;
$person_meldung->geschlecht = UPPER($person->geschlecht);
$person_meldung->staat = $person->staatsbuergerschaft;
if ($person->svnr != '')
$person_meldung->svnr = $person->svnr;
// PLZ der Meldeadresse laden
$adresse = new adresse();
if ($adresse->loadZustellAdresse($person->person_id))
$person_meldung->plz = $row->plz;
// ZGV Datum laden falls vorhanden
$prestudent = new prestudent();
if ($prestudent->load($prestudent_id) && $prestudent->zgvdatum != '')
{
$datum_obj = new datum();
$person->matura = $datum_obj->formatDatum($matura, 'Ymd');
}
// Meldung der Vergabe der Matrikelnummer
if ($this->setMatrikelnummer(DVB_BILDUNGSEINRICHTUNG_CODE, $person))
{
// Matrikelnummer bei Person speichern
$person->matr_nr = $matrikelnummer;
if ($person->save())
{
$this->logRequest($person, 'assignNewMatrikelnummer', true, $matrikelnummer);
return true;
}
}
else
{
$this->logRequest($person, 'assignNewgMatrikelnummer', false, $person_meldung);
$this->errormsg .= 'Vergabe fehlgeschlagen';
return false;
}
}
else
{
$this->logRequest($person, 'assignNewgMatrikelnummer', false, $studienjahr);
$this->errormsg .= 'Failed to get Kontingent';
return false;
}
}
}
/**
* Performs a OAuth2 Authentication and returns the OAuth Bearer Token
* @return boolean true wenn erfolgreich, false im Fehlerfall
*/
public function authenticate()
{
$this->debug('Request new OAuth Token');
$curl = curl_init();
$url = self::DVB_URL_WEBSERVICE_OAUTH;
$url .= '?grant_type=client_credentials';
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$headers = array(
'Accept: application/json',
'Content-Type: application/x-www-form-urlencoded',
'Authorization: Basic '.base64_encode($this->username.":".$this->password),
'User-Agent: FHComplete',
'Connection: Keep-Alive',
'Expect:',
'Content-Length: 0'
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$this->debug('Sending Request to '.$url);
$json_response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
curl_close($curl);
$this->debug('Response: '.$curl_info['http_code']);
if ($curl_info['http_code'] == '200')
{
/* Example Response:
{
"access_token": "d9c60404-1530-4b05-bb8e-0a0b0f321726",
"token_type": "bearer",
"expires_in": 41087,
"scope": "read write ROLE_bildungseinrichtung
ROLE_bildungseinrichtung_A"
}
*/
$this->authentication = json_decode($json_response);
// Calculate Expire Date
$ttl = new DateTime();
$ttl->add(new DateInterval('PT'.$this->authentication->expires_in.'S'));
$this->authentication->DateTimeExpires = $ttl;
$this->debug('Access_token:'.$this->authentication->access_token);
$this->debug('Scope:'.$this->authentication->scope);
return true;
}
else
{
$this->errormsg = 'Authentication failed with HTTP Code:'.$curl_info['http_code'];
$this->errormsg .= ' and Response:'.$json_response;
return false;
}
}
/**
* Checks if the Token is Expired
* @return boolean true if expired, false if valid.
*/
private function tokenIsExpired()
{
if (!isset($this->authentication))
return true;
$dtnow = new DateTime();
if ($this->authentication->DateTimeExpires < $dtnow)
{
return true;
}
else
return false;
}
/**
* Get Matrikelnummer by Social Security Number
* @param string $svnr Social Security Number.
* @return Matrikelnummer or false on error.
*/
public function getMatrikelnrBySVNR($svnr)
{
if ($this->tokenIsExpired())
{
if (!$this->authenticate())
return false;
}
$this->debug('getMatrikelnrBySVNR');
$curl = curl_init();
$url = self::DVB_URL_WEBSERVICE_SVNR;
$url .= '?sozialVersicherungsNummer='.curl_escape($curl, $svnr);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$headers = array(
'Accept: application/json',
'Authorization: Bearer '.$this->authentication->access_token,
'User-Agent: FHComplete',
'Connection: Keep-Alive',
'Expect:',
'Content-Length: 0'
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$this->debug('Sending Request to '.$url);
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
curl_close($curl);
$this->debug('ResponseCode: '.$curl_info['http_code']);
$this->debug('ResponseData: '.print_r($response, true));
if ($curl_info['http_code'] == '200')
{
/* Example Response:
12345678
Max
Mustermann
M
1999-02-19
A
*/
$dom = new DOMDocument();
$dom->loadXML($response);
$namespace = 'http://www.brz.gv.at/datenverbund-unis';
$domnodes_student = $dom->getElementsByTagNameNS($namespace, 'student');
foreach ($domnodes_student as $row_student)
{
// Wenn nicht gesperrt und fix vergeben
$ingesamtpool = $row_student->getAttribute('inGesamtPool');
$gesperrt = $row_student->getAttribute('gesperrt');
if ($ingesamtpool == 'true' && $gesperrt == 'false')
{
$domnodes_matrikelnummer = $row_student->getElementsByTagNameNS($namespace, 'matrikelNummer');
foreach ($domnodes_matrikelnummer as $row)
{
// Found
return $row->textContent;
}
}
}
$this->errormsg = '';
return false;
}
else
{
$this->errormsg = 'Request Failed with HTTP Code:'.$curl_info['http_code'].' and Response:'.$response;
return false;
}
}
/**
* Get Matrikelnummer by Ersatzkennzeichen
* @param string $ersatzkennzeichen Ersatzkennzeichen to search for.
* @return Matrikelnummer or false
*/
public function getMatrikelnrByErsatzkennzeichen($ersatzkennzeichen)
{
if ($this->tokenIsExpired())
{
if (!$this->authenticate())
return false;
}
$this->debug('getMatrikelnrByErsatzkennzeichen');
$curl = curl_init();
$url = self::DVB_URL_WEBSERVICE_ERSATZKZ;
$url .= '?ersatzKennzeichen='.curl_escape($curl, $ersatzkennzeichen);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$headers = array(
'Accept: application/json',
'Authorization: Bearer '.$this->authentication->access_token,
'User-Agent: FHComplete',
'Connection: Keep-Alive',
'Expect:',
'Content-Length: 0'
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$this->debug('Sending Request to '.$url);
$xml_response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
curl_close($curl);
$this->debug('ResponseCode: '.$curl_info['http_code']);
$this->debug('ResponseData: '.print_r($response, true));
if ($curl_info['http_code'] == '200')
{
/* Example Response Success
A
12345678
2017S
ABCD201093
Bc.
Max
Mustermann
W
1993-06-26
TCH
A
1030
Wien
Obere Bahngasse 20/12
A
1030
Wien
Obere Bahngasse 20/12
12345678
Max
Mustermann
W
1993-06-26
TCH
*/
/* 200 - No Entry found
*/
/* 401 Error Code Token Expired
{
"error": "invalid_token",
"error_description": "Access token expired: 64a58ef3-1a70-46e9-b44f-35cc5051ae8e"
}
*/
/* 400 Bad Request
318e1bc5-279d-43c4-af47-5e6df2ff5279
ZD00001
Z
Der Server konnte die Anfrage nicht vearbeiten.
Required String parameter 'ersatzKennzeichen' is not present
*/
$dom = new DOMDocument();
$dom->loadXML($xml_response);
$namespace = 'http://www.brz.gv.at/datenverbund-unis';
$domnodes_student = $dom->getElementsByTagNameNS($namespace, 'student');
foreach ($domnodes_student as $row_student)
{
// Wenn nicht gesperrt und fix vergeben
$ingesamtpool = $row_student->getAttribute('inGesamtPool');
$gesperrt = $row_student->getAttribute('gesperrt');
if ($ingesamtpool == 'true' && $gesperrt == 'false')
{
$domnodes_matrikelnummer = $row_student->getElementsByTagNameNS($namespace, 'matrikelNummer');
foreach ($domnodes_matrikelnummer as $row)
{
// Found
return $row->textContent;
}
}
}
$this->errormsg = '';
return false;
}
else
{
$this->errormsg = 'Request Failed with HTTP Code:'.$curl_info['http_code'].' and Response:'.$xml_response;
return false;
}
}
/**
* List of already Reserved Matrikelnummern
* @param string $bildungseinrichtung Shortname of Institution.
* @param string $studienjahr Year of Reservation.
* @return array with reserved Matrikelnr. or false on failure.
*/
public function getReservations($bildungseinrichtung, $studienjahr)
{
$this->debug('getReservations');
$uuid = $this->getUUID();
if ($this->tokenIsExpired())
{
if (!$this->authenticate())
return false;
}
$curl = curl_init();
$url = self::DVB_URL_WEBSERVICE_RESERVIERUNG;
$url .= '?uuid='.curl_escape($curl, $uuid);
$url .= '&be='.curl_escape($curl, $bildungseinrichtung);
$url .= '&sj='.curl_escape($curl, $studienjahr);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$headers = array(
'Accept: application/xml',
'Authorization: Bearer '.$this->authentication->access_token,
'User-Agent: FHComplete',
'Connection: Keep-Alive',
'Expect:',
'Content-Length: 0'
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$this->debug('Request URL:'.$url);
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
curl_close($curl);
$this->debug('ResponseCode: '.$curl_info['http_code']);
$this->debug('ResponseData: '.print_r($response, true));
/* 200 ok
793d44fa-5646-42b1-b0cb-f2f121b2f14f
12345678
23456789
*/
if ($curl_info['http_code'] == '200')
{
$dom = new DOMDocument();
$dom->loadXML($response);
$domnodes_matrikelnummer = $dom->getElementsByTagName('matrikelnummer');
$reservations = array();
foreach ($domnodes_matrikelnummer as $row)
{
$reservations[] = $row->textContent;
}
return $reservations;
}
else
{
$this->errormsg = 'Request Failed with HTTP Code:'.$curl_info['http_code'].' and Response:'.$response;
return false;
}
}
/**
* Request a new Matrikelnummer
* @param string $bildungseinrichtung Shortname of Institution.
* @param string $studienjahr Year of issuing.
* @param int $anzahl Number of Requested Numbers.
* @return array list of matrikelnr or false on failure.
*/
public function getKontingent($bildungseinrichtung, $studienjahr, $anzahl = 1)
{
$this->debug('getKontingent');
$uuid = $this->getUUID();
if ($this->tokenIsExpired())
{
if (!$this->authenticate())
return false;
}
$data = '
'.$uuid.'
'.$anzahl.'
'.$bildungseinrichtung.'
'.$studienjahr.'
';
$curl = curl_init();
$url = self::DVB_URL_WEBSERVICE_RESERVIERUNG;
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$headers = array(
'Accept: application/xml',
'Content-Type: application/xml',
'Authorization: Bearer '.$this->authentication->access_token,
'User-Agent: FHComplete',
'Connection: Keep-Alive',
'Expect:'
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$this->debug('Request URL:'.$url);
$this->debug('Request Data:'.$data);
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
curl_close($curl);
$this->debug('ResponseCode: '.$curl_info['http_code']);
$this->debug('ResponseData: '.print_r($response, true));
if ($curl_info['http_code'] == '200')
{
$dom = new DOMDocument();
$dom->loadXML($response);
$domnodes_matrikelnummer = $dom->getElementsByTagName('matrikelnummer');
$kontingent = array();
foreach ($domnodes_matrikelnummer as $row)
{
$kontingent[] = $row->textContent;
}
return $kontingent;
}
else
{
$this->errormsg = 'Request Failed with HTTP Code:'.$curl_info['http_code'].' and Response:'.$response;
return false;
}
}
/**
* Meldet die Vergabe der Matrikelnummer
* @param string $bildungseinrichtung Kennzeichen der Bildungseinrichtung.
* @param object $person Objekt mit den Personendaten.
* @return booelan true wenn erfolgreich
*/
public function setMatrikelnummer($bildungseinrichtung, $person)
{
$this->debug('setMatrikelnummer');
$uuid = $this->getUUID();
if ($this->tokenIsExpired())
{
if (!$this->authenticate())
return false;
}
$data = '
'.$uuid.'
'.$bildungseinrichtung.'
'.$person->geburtsdatum.'
'.$person->geschlecht.'
'.$person->matrikelnummer.'';
if (isset($person->matura) && $person->matura != '')
$data .= ''.$person->matura.'';
else
$data .= '00000000';
$data .= ''.$person->nachname.'';
if (isset($person->plz) && $person->plz != '')
$data .= ''.$person->plz.'';
$data .= ''.$person->staat.'';
if (isset($person->svnr) && $person->svnr != '')
$data .= ''.$person->svnr.'';
$data .= ''.$person->vorname.'';
if (isset($person->writeonerror) && $person->writeonerror === true)
$data .= 'J';
$data .= '
';
$curl = curl_init();
$url = self::DVB_URL_WEBSERVICE_MELDUNG;
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$headers = array(
'Accept: application/xml',
'Content-Type: application/xml',
'Authorization: Bearer '.$this->authentication->access_token,
'User-Agent: FHComplete',
'Connection: Keep-Alive',
'Expect:'
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$this->debug('Request URL:'.$url);
$this->debug('Request Data:'.$data);
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
curl_close($curl);
$this->debug('Response: '.$curl_info['http_code']);
$this->debug('Response: '.print_r($response, true));
/* 200 Fehlermeldung
b76e84a9-c0bd-494c-97cb-c4ab9cd452c5
ZD01471
90
UNI-Kennzeichen
UNI-Kennzeichen fehlt oder ungültig (FHTEST)
BRZ
FHTEST
AG21333
65
Datum allg.Univ.reife
kein gültiges Datum oder Format
Korrektur Datum allg. Univ.reife oder 000000 angeben, falls nicht anwendbar
leer
ZD10073
90
Matrikelnummer
aus ungültigem Kontingent
Korrektur der Matrikelnummer
12345678
*/
/* 200 ok
8b239582-6bc5-4193-ac79-2dcf9ec96439
*/
if ($curl_info['http_code'] == '200')
{
$dom = new DOMDocument();
$dom->loadXML($response);
$domnodes_fehlerliste = $dom->getElementsByTagName('fehlerliste');
$fehleranzahl = $domnodes_fehlerliste[0]->getAttribute('fehleranzahl');
if ($fehleranzahl === '0')
{
// Keine Fehler -> Meldung erfolgreich
return true;
}
else
{
$this->errormsg = 'Es gab '.$fehleranzahl.' Fehler:';
$domnodes_fehler = $dom->getElementsByTagName('fehler');
foreach ($domnodes_fehler as $row)
{
$datenfeld = $row->getElementsByTagName('datenfeld');
$fehlertext = $row->getElementsByTagName('fehlertext');
$this->errormsg .= ' Datenfeld:'.$datenfeld[0]->textContent;
$this->errormsg .= ' Fehlertext:'.$fehlertext[0]->textContent;
}
return false;
}
}
else
{
$this->errormsg = 'Request Failed with HTTP Code:'.$curl_info['http_code'].' and Response:'.$response;
return false;
}
}
/**
* Generiert eine eindeutige UUID
* @return uuid
*/
private function getUUID()
{
$data = openssl_random_pseudo_bytes(16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
/**
* Erstellt eine Debug Message
* @param string $msg Message to log.
* @return void
*/
private function debug($msg)
{
if ($this->debug)
$this->debug_output .= "\n
".date('Y-m-d H:i:s').': '.htmlentities($msg);
}
/**
* Erstellt einen Logeintrag
* @param object $person Personen objekt.
* @param string $typ Art des Requests.
* @param bool $result True wen Erfolgreich, false wenn Fehlerhaft.
* @param object $data Zusatzdaten die Übermittelt wurden und geloggt werden sollen.
* @return void
*/
public function logRequest($person, $typ, $result, $data = null)
{
$webservicelog = new webservicelog();
$webservicelog->webservicetyp_kurzbz = 'dvb';
$webservicelog->request_id = $person->person_id;
$webservicelog->beschreibung = $typ;
$webservicelog->request_data = ($result?'SUCCESS':'FAILED').' '.$this->errormsg;
if (!is_null($data))
$webservicelog->request_data .= ' '.print_r($data, true);
$webservicelog->save();
}
}