diff --git a/cis/private/tools/zeitaufzeichnung.php b/cis/private/tools/zeitaufzeichnung.php index 8c7f4d1dc..02dcc20eb 100644 --- a/cis/private/tools/zeitaufzeichnung.php +++ b/cis/private/tools/zeitaufzeichnung.php @@ -44,6 +44,7 @@ require_once('../../../include/globals.inc.php'); require_once('../../../include/bisverwendung.class.php'); require_once('../../../include/studiensemester.class.php'); require_once('../../../include/benutzerberechtigung.class.php'); +require_once('../../../include/zeitaufzeichnung_csv_import.class.php'); function checkZeitsperren($p, $uid, $day) { @@ -867,28 +868,6 @@ if($kartennummer != '') } //Speichern der Daten -function checkVals ($oe_val, $project_val, $phase_val, $service_val) -{ - $error = 0; - if ($service_val && ( filter_var($service_val, FILTER_VALIDATE_INT) === false )) - $error = 1; - if ($phase_val && ( filter_var($phase_val, FILTER_VALIDATE_INT) === false )) - $error = 1; - if ($oe_val) - { - $oecheck = new organisationseinheit($oe_val); - if ($oecheck->errormsg) - $error = 1; - } - if ($project_val) - { - $procheck = new projekt($project_val); - if ($procheck->errormsg) - $error = 1; - } - return $error; -} - if(isset($_POST['save']) || isset($_POST['edit']) || isset($_POST['import'])) { $zeit = new zeitaufzeichnung(); @@ -914,206 +893,10 @@ if(isset($_POST['save']) || isset($_POST['edit']) || isset($_POST['import'])) if ($_FILES['csv']['error'] == 0 && isset($_POST['import'])) { - $name = $_FILES['csv']['name']; - $tmpName = $_FILES['csv']['tmp_name']; - $mimeType = mime_content_type($_FILES['csv']['tmp_name']); - //echo($mimeType); - if($mimeType=='text/plain') - { - if(($handle = fopen($tmpName, 'r')) !== FALSE) - { - if (mb_detect_encoding(fgets($handle), 'UTF-8', true)) - { - set_time_limit(0); - $anzahl = 0; - $importtage_array = array(); - $ende_vorher = date('Y-m-d H:i:s'); - - while(($data = fgetcsv($handle, 1000, ';', '"')) !== FALSE) - { - if($data[0] == $user){ - if(!empty($data[6]) && !in_array($data[6], $project_kurzbz_array) && empty($data[7])) - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich, da Sie folgendem Projekt entweder nicht zugewiesen sind oder das Projekt schon abgeschlossen wurde: ('.$data[6].')
'; - } - elseif(!empty($data[7]) && !in_array($data[7], $projectphasen_kurzbz_array)) - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich, da Sie folgender Projektphase entweder nicht zugewiesen sind oder die Projektphase schon abgeschlossen wurde: ('.$data[7].')
'; - } - else - { - $vonCSV = $datum->formatDatum($data[2], $format = 'Y-m-d'); - $bisCSV = $datum->formatDatum($data[3], $format = 'Y-m-d'); - $dateVonCSV = new DateTime($vonCSV); - $dateBisCSV = new DateTime($bisCSV); - $extractHourBis = $datum->formatDatum($data[3], $format = 'H:i:s'); - - if (!isset($data[5])) - $data[5] = NULL; - if (!isset($data[6])) - $data[6] = NULL; - if (!isset($data[7])) - $data[7] = NULL; - if (!isset($data[8])) - $data[8] = NULL; - - $zscheck = checkZeitsperren($p, $user, $vonCSV); - if( $zscheck['status'] === false ) { - echo '' . $p->t("global/fehlerBeimSpeichernDerDaten") . ': ' . $zscheck['msg'] . '
'; - } - elseif ($datum->formatDatum($data[2], $format='Y-m-d H:i:s') < $sperrdatum) - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich da vor dem Sperrdatum ('.$data[2].')
'; - elseif ($datum->formatDatum($data[2], $format='Y-m-d H:i:s') > $limitdatum) - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich da ('.$data[2].') zu weit in der Zukunft liegt.
'; - elseif ($dateVonCSV!=$dateBisCSV && $data[1]!="DienstreiseMT") - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich, da keine Zeitaufzeichnung über mehrere Tage erlaubt ist (ausgenommen Dienstreisen).
'; - } - elseif ($extractHourBis == '00:00:00') - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Bitte Arbeitszeiten gemäß Arbeitsaufzeichnung Leitfaden tagesgenau abgrenzen: Nur Eingaben von 00:00 bis 23:59 erlaubt!
'; - } - elseif (empty($data[7]) && !empty($data[6]) && !$projects_of_user->checkProjectInCorrectTime($data[6], $data[2], $data[3])) - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich, da angegebenes Anfangs und Enddatum nicht in den Projektzeitrahmen fällt: ('.$data[2].') ('.$data[3].')
'; - } - elseif (!empty($data[7]) && !$projektph_of_user ->checkProjectphaseInCorrectTime($data[7], $data[2], $data[3])) - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich, da angegebenes Anfangs und Enddatum nicht in den Projektphasenzeitrahmen fällt: ('.$data[2].') ('.$data[3].')
'; - } - elseif (checkVals($data[5],$data[6],$data[7],$data[8])) - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Fehlerhafte Werte ('.$data[2].')
'; - } - else - { - if ($data[1] == 'LehreIntern') - $data[1] = 'Lehre'; - $zeit->new = true; - $zeit->beschreibung = NULL; - $zeit->oe_kurzbz_1 = NULL; - $zeit->projekt_kurzbz = NULL; - $zeit->projektphase_id = NULL; - $zeit->service_id = NULL; - - $zeit->insertamum = date('Y-m-d H:i:s'); - $zeit->updateamum = date('Y-m-d H:i:s'); - $zeit->updatevon = $user; - $zeit->insertvon = $user; - $zeit->uid = $data[0]; - $zeit->aktivitaet_kurzbz = $data[1]; - $zeit->start = $datum->formatDatum($data[2], $format='Y-m-d H:i:s'); - $zeit->ende = $datum->formatDatum($data[3], $format='Y-m-d H:i:s'); - if (isset($data[4])) - $zeit->beschreibung = $data[4]; - if (isset($data[5])) - $zeit->oe_kurzbz_1 = $data[5]; - if (isset($data[6])) - $zeit->projekt_kurzbz = $data[6]; - if (isset($data[7])) - $zeit->projektphase_id = $data[7]; - if (isset($data[8])) - $zeit->service_id = $data[8]; - if (isset($data[9])) - { - if (strtolower($data[9] == 'true')) - { - // check, ob homeoffice gemäß Bisverwendung - $verwendung = new bisverwendung(); - $verwendung->getVerwendungDatum($data[0],$vonCSV); - - foreach ($verwendung->result as $v) - if ($v->homeoffice) - { - $zeit->homeoffice = true; - } - else - { - echo ''.$p->t("zeitaufzeichnung/homeofficeNichtErlaubt", ($vonCSV)) .'
'; - $zeit->homeoffice = false; - } - } - else - { - $zeit->homeoffice = false; - } - } - else - { - $zeit->homeoffice = false; - } - $tag = $datum->formatDatum($data[2], $format='Y-m-d'); - - if(!in_array($tag, $importtage_array)) - { - $importtage_array[] = $tag; - $zeit->deleteEntriesForUser($user, $tag); - $tag_aktuell = $tag; - } - else - { - if ($ende_vorher < $zeit->start) - { - $pause = new zeitaufzeichnung(); - $pause->new = true; - $pause->insertamum = date('Y-m-d H:i:s'); - $pause->updateamum = date('Y-m-d H:i:s'); - $pause->updatevon = $user; - $pause->insertvon = $user; - $pause->uid = $user; - $pause->aktivitaet_kurzbz = 'Pause'; - $pause->start = $ende_vorher; - $pause->ende = $zeit->start; - $pause->beschreibung = ''; - $pause->homeoffice = $homeoffice; - if(!$pause->save()) - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': '.$pause->errormsg.'
'; - } - } - } - - $ende_vorher = $zeit->ende; - if($data[2] != $data[3]) - { - /* - if ($data[1] == 'LehreExtern') - { - $zeit->start = date('Y-m-d H:i:s', strtotime('+2 seconds', strtotime($data[2]))); - $zeit->ende = date('Y-m-d H:i:s', strtotime('-2 seconds', strtotime($data[3]))); - } - */ - if(!$zeit->save()) - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': '.$zeit->errormsg.'('.$zeit->start.')
'; - } - else - $anzahl++; - } - else - $anzahl++; - - } - } - } - else if (strpos($data[0],'#') === false) - { - echo ''.$p->t("global/fehlerBeimSpeichernDerDaten").': Falsche UID nicht importiert ('.$data[0].')
'; - } - } - if($anzahl>0) - { - echo ''.$p->t("global/datenWurdenGespeichert").' ('.$anzahl.')'; - foreach ($importtage_array as $ptag) - { - $zeit->cleanPausenForUser($user, $ptag); - } - } - } - else - echo 'Datei konnte nicht importiert werden. Encoding ist nicht UTF-8!'; - } - } + $zeit_csv_import = new zeitaufzeichnung_csv_import($p, $zeit, $project_kurzbz_array, $projectphasen_kurzbz_array, $sperrdatum, $limitdatum, $projects_of_user, $projektph_of_user, $datum, $user); + $zeit_csv_import->parseCSV(); + echo $zeit_csv_import->InfosToHTML(); + echo $zeit_csv_import->ErrorsToHTML(); } else if ($datum->formatDatum($von, $format='Y-m-d H:i:s') < $sperrdatum) echo '' .$p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich da vor dem Sperrdatum'; diff --git a/include/zeitaufzeichnung_csv_import.class.php b/include/zeitaufzeichnung_csv_import.class.php new file mode 100644 index 000000000..23cf16037 --- /dev/null +++ b/include/zeitaufzeichnung_csv_import.class.php @@ -0,0 +1,433 @@ +p = $p; + $this->zeit = $zeit; + + $this->project_kurzbz_array = $project_kurzbz_array; + $this->projectphasen_kurzbz_array = $projectphasen_kurzbz_array; + + $this->sperrdatum = $sperrdatum; + $this->limitdatum = $limitdatum; + + $this->projects_of_user = $projects_of_user; + $this->projektph_of_user = $projektph_of_user; + + $this->datum = $datum; + + $this->user = $user; + $this->errors = array(); + $this->infos = array(); + } + + public function parseCSV() { + $this->tmpname = $_FILES['csv']['tmp_name']; + try { + $this->checkMimeType(); + $this->openFileForReading(); + $this->checkEncoding(); + $this->iterateRows(); + $this->checkAndCleanup(); + } catch (Exception $ex) { + $this->addError($ex->getMessage()); + } + } + + public function hasErrors() { + return !empty($this->errors); + } + + public function hasInfos() { + return !empty($this->infos); + } + + public function ErrorsToHTML() { + $html = ''; + foreach ($this->errors as $msg) { + $html .= '' . $msg . '
' . "\n"; + } + return $html; + } + + public function InfosToHTML() { + $html = ''; + foreach ($this->infos as $msg) { + $html .= '' . $msg . '
' . "\n"; + } + return $html; + } + + protected function addError($msg, $prepend_current_line=false) { + if( $prepend_current_line ) { + $msg = 'Zeile ' . $this->current_line . ' - ' . $msg; + } + $this->errors[] = $msg; + } + + protected function addInfo($msg) { + $this->infos[] = $msg; + } + + protected function checkMimeType() { + $mimeType = mime_content_type($this->tmpname); + if( $mimeType !== 'text/plain' ) { + throw new Exception('Datei ist nicht im CSV Format.'); + } + } + + protected function openFileForReading() { + if( false === ($this->fh = fopen($this->tmpname, 'r')) ) + { + throw new Exception('CSV - Datei konnte nicht zum lesen geöffnet werden.'); + } + } + + protected function checkEncoding() { + $filecontent = file_get_contents($this->tmpname); + if( !mb_detect_encoding($filecontent, 'UTF-8', true) ) { + throw new Exception('Datei konnte nicht importiert werden. Encoding ist nicht UTF-8!'); + } + } + + protected function iterateRows() { + set_time_limit(0); + $this->anzahl = 0; + $this->importtage_array = array(); + $this->ende_vorher = date('Y-m-d H:i:s'); + + $this->data = null; + $this->current_line = 0; + while(($this->data = fgetcsv($this->fh, 1000, ';', '"')) !== FALSE) + { + if( false !== strpos($this->data[self::USER], '#') ) { + // ignore lines starting with # + continue; + } + $this->current_line++; + $this->processData(); + } + } + + protected function processData() { + try { + $this->checkUser(); + $this->checkProject(); + $this->checkPhase(); + $this->initData(); + $this->checkZeitsperren(); + $this->checkSperrdatum(); + $this->checkLimitdatum(); + $this->checkDienstreise(); + $this->checkTagesgenau(); + $this->checkProjectInterval(); + $this->checkPhaseInterval(); + $this->checkVals(); + $this->mapLehreIntern(); + $this->prepareZeitaufzeichnung(); + $this->checkImporttage(); + $this->saveZeit(); + } catch (Exception $ex) { + $this->addError($ex->getMessage(), true); + } + } + + protected function checkUser() { + if( $this->data[self::USER] !== $this->user && (strpos($this->data[self::USER],'#') !== false) ) + { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten").': Falsche UID nicht importiert ('.$this->data[self::USER].')'); + } + } + + protected function checkProject() { + if(!empty($this->data[self::PROJEKT]) && !in_array($this->data[self::PROJEKT], $this->project_kurzbz_array) && empty($this->data[self::PHASE])) + { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich, da Sie folgendem Projekt entweder nicht zugewiesen sind oder das Projekt schon abgeschlossen wurde: ('.$this->data[self::PROJEKT].')'); + } + + } + + protected function checkPhase() { + if(!empty($this->data[self::PHASE]) && !in_array($this->data[self::PHASE], $this->projectphasen_kurzbz_array)) + { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten").': Eingabe nicht möglich, da Sie folgender Projektphase entweder nicht zugewiesen sind oder die Projektphase schon abgeschlossen wurde: ('.$this->data[self::PHASE].')'); + } + } + + protected function initData() { + if (!isset($this->data[self::OE])) { + $this->data[self::OE] = NULL; + } + if (!isset($this->data[self::PROJEKT])) { + $this->data[self::PROJEKT] = NULL; + } + if (!isset($this->data[self::PHASE])) { + $this->data[self::PHASE] = NULL; + } + if (!isset($this->data[self::SERVICE])) { + $this->data[self::SERVICE] = NULL; + } + } + + protected function checkZeitsperren() { + $zscheck = checkZeitsperren($this->p, $this->user, $this->datum->formatDatum($this->data[self::STARTDT], $format = 'Y-m-d')); + if ($zscheck['status'] === false) { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten") . ": " . $zscheck['msg']); + } + } + + protected function checkSperrdatum() { + if ($this->datum->formatDatum($this->data[self::STARTDT], $format='Y-m-d H:i:s') < $this->sperrdatum) { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten") + .': Eingabe nicht möglich da vor dem Sperrdatum ('.$this->data[self::STARTDT].')'); + } + + } + + protected function checkLimitdatum() { + if ($this->datum->formatDatum($this->data[self::STARTDT], $format='Y-m-d H:i:s') > $this->limitdatum) { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten") + .': Eingabe nicht möglich da ('.$this->data[self::STARTDT].') zu weit in der Zukunft liegt.'); + } + } + + protected function checkDienstreise() { + $vonCSV = $this->datum->formatDatum($this->data[self::STARTDT], $format='Y-m-d'); + $bisCSV = $this->datum->formatDatum($this->data[self::ENDEDT], $format='Y-m-d'); + $dateVonCSV = new DateTime($vonCSV); + $dateBisCSV = new DateTime($bisCSV); + if ($dateVonCSV!=$dateBisCSV && $this->data[self::AKTIVITAET]!="DienstreiseMT") + { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten") + .': Eingabe nicht möglich, da keine Zeitaufzeichnung über mehrere Tage erlaubt ist (ausgenommen Dienstreisen).'); + } + } + + protected function checkTagesgenau() { + $bisHour = $this->datum->formatDatum($this->data[self::ENDEDT], $format = 'H:i:s'); + if ($bisHour == '00:00:00') { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten") + .': Bitte Arbeitszeiten gemäß Arbeitsaufzeichnung Leitfaden tagesgenau abgrenzen: Nur Eingaben von 00:00 bis 23:59 erlaubt!'); + } + } + + protected function checkProjectInterval() { + if (empty($this->data[self::PHASE]) && !empty($this->data[self::PROJEKT]) + && !$this->projects_of_user->checkProjectInCorrectTime($this->data[self::PROJEKT], $this->data[self::STARTDT], $this->data[self::ENDEDT])) + { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten") + .': Eingabe nicht möglich, da angegebenes Anfangs und Enddatum nicht in den Projektzeitrahmen fällt: (' + .$this->data[self::STARTDT].') ('.$this->data[self::ENDEDT].')'); + } + } + + protected function checkPhaseInterval() { + if (!empty($this->data[self::PHASE]) && !$this->projektph_of_user->checkProjectphaseInCorrectTime($this->data[self::PHASE], $this->data[self::STARTDT], $this->data[self::ENDEDT])) + { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten") + .': Eingabe nicht möglich, da angegebenes Anfangs und Enddatum nicht in den Projektphasenzeitrahmen fällt: (' + .$this->data[self::STARTDT].') ('.$this->data[self::ENDEDT].')'); + } + } + + protected function checkVals() { + $failedvals = $this->_checkVals($this->data[self::OE],$this->data[self::PROJEKT],$this->data[self::PHASE],$this->data[self::SERVICE]); + if( count($failedvals) > 0 ) + { + throw new Exception($this->p->t("global/fehlerBeimSpeichernDerDaten").': Fehlerhafte Werte ('.implode(', ', $failedvals).')'); + } + } + + protected function _checkVals ($oe_val, $project_val, $phase_val, $service_val) { + $error = array(); + if ($service_val && ( filter_var($service_val, FILTER_VALIDATE_INT) === false )) { + $error[] = 'service'; + } + if ($phase_val && ( filter_var($phase_val, FILTER_VALIDATE_INT) === false )) { + $error[] = 'phase'; + } + if ($oe_val) { + $oecheck = new organisationseinheit($oe_val); + if ($oecheck->errormsg) { + $error[] = 'OE'; + } + } + if ($project_val) { + $procheck = new projekt($project_val); + if ($procheck->errormsg) { + $error[] = 'projekt'; + } + } + return $error; + } + + protected function mapLehreIntern() { + if ($this->data[self::AKTIVITAET] == 'LehreIntern') { + $this->data[self::AKTIVITAET] = 'Lehre'; + } + } + + protected function prepareZeitaufzeichnung() { + $this->zeit->new = true; + $this->zeit->beschreibung = NULL; + $this->zeit->oe_kurzbz_1 = NULL; + $this->zeit->projekt_kurzbz = NULL; + $this->zeit->projektphase_id = NULL; + $this->zeit->service_id = NULL; + + $this->zeit->insertamum = date('Y-m-d H:i:s'); + $this->zeit->updateamum = date('Y-m-d H:i:s'); + $this->zeit->updatevon = $this->user; + $this->zeit->insertvon = $this->user; + $this->zeit->uid = $this->data[self::USER]; + $this->zeit->aktivitaet_kurzbz = $this->data[self::AKTIVITAET]; + $this->zeit->start = $this->datum->formatDatum($this->data[self::STARTDT], $format='Y-m-d H:i:s'); + $this->zeit->ende = $this->datum->formatDatum($this->data[self::ENDEDT], $format='Y-m-d H:i:s'); + if (isset($this->data[self::BESCHREIBUNG])) { + $this->zeit->beschreibung = $this->data[self::BESCHREIBUNG]; + } + if (isset($this->data[self::OE])) { + $this->zeit->oe_kurzbz_1 = $this->data[self::OE]; + } + if (isset($this->data[self::PROJEKT])) { + $this->zeit->projekt_kurzbz = $this->data[self::PROJEKT]; + } + if (isset($this->data[self::PHASE])) { + $this->zeit->projektphase_id = $this->data[self::PHASE]; + } + if (isset($this->data[self::SERVICE])) { + $this->zeit->service_id = $this->data[self::SERVICE]; + } + $this->zeit->homeoffice = false; + if (isset($this->data[self::HOMEOFFICE])) { + $this->zeit->homeoffice = (strtolower($this->data[self::HOMEOFFICE]) == 'true'); + if (strtolower($this->data[self::HOMEOFFICE]) == 'true') { + // check, ob homeoffice gemäß Bisverwendung + $vonCSV = $this->datum->formatDatum($this->data[self::STARTDT], $format = 'Y-m-d'); + $verwendung = new bisverwendung(); + $verwendung->getVerwendungDatum($this->data[self::USER], $vonCSV); + + foreach ($verwendung->result as $v) { + if ($v->homeoffice) { + $this->zeit->homeoffice = true; + } else { + $this->addError($this->p->t("zeitaufzeichnung/homeofficeNichtErlaubt", ($vonCSV))); + $this->zeit->homeoffice = false; + } + } + } + } + } + + protected function checkImporttage() { + $tag = $this->datum->formatDatum($this->data[self::STARTDT], $format='Y-m-d'); + + if(!in_array($tag, $this->importtage_array)) + { + $this->importtage_array[] = $tag; + $this->zeit->deleteEntriesForUser($this->user, $tag); + $tag_aktuell = $tag; + } + else if ($this->ende_vorher < $this->zeit->start) + { + $this->savePause(); + } + + $this->ende_vorher = $this->zeit->ende; + } + + protected function savePause() { + $pause = new zeitaufzeichnung(); + $pause->new = true; + $pause->insertamum = date('Y-m-d H:i:s'); + $pause->updateamum = date('Y-m-d H:i:s'); + $pause->updatevon = $this->user; + $pause->insertvon = $this->user; + $pause->uid = $this->user; + $pause->aktivitaet_kurzbz = 'Pause'; + $pause->start = $this->ende_vorher; + $pause->ende = $this->zeit->start; + $pause->beschreibung = ''; + $pause->homeoffice = $this->zeit->homeoffice; + if(!$pause->save()) + { + $this->addError($this->p->t("global/fehlerBeimSpeichernDerDaten").': '.$pause->errormsg, true); + } + } + + protected function saveZeit() { + if($this->data[self::STARTDT] != $this->data[self::ENDEDT]) + { + if(!$this->zeit->save()) + { + $this->addError($this->p->t("global/fehlerBeimSpeichernDerDaten").': '.$this->zeit->errormsg.'('.$this->zeit->start.')', true); + } + else { + $this->anzahl++; + } + } + else { + $this->anzahl++; + } + } + + protected function checkAndCleanup() { + if($this->anzahl>0) + { + $this->addInfo($this->p->t("global/datenWurdenGespeichert").' ('.$this->anzahl.')'); + foreach ($this->importtage_array as $ptag) + { + $this->zeit->cleanPausenForUser($this->user, $ptag); + } + } + } +}