{"id":644,"date":"2021-06-20T19:55:22","date_gmt":"2021-06-20T17:55:22","guid":{"rendered":"https:\/\/www.montybanse.eu\/?p=644"},"modified":"2022-03-06T18:23:27","modified_gmt":"2022-03-06T17:23:27","slug":"dms-das-herzstueck","status":"publish","type":"post","link":"https:\/\/www.montybanse.eu\/index.php\/server-programmierung-co\/dms-das-herzstueck\/","title":{"rendered":"DMS: Das Herzst\u00fcck"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"644\" class=\"elementor elementor-644\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-74bb185 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"74bb185\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4e35451\" data-id=\"4e35451\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-8f52b77 elementor-drop-cap-yes elementor-drop-cap-view-default elementor-widget elementor-widget-text-editor\" data-id=\"8f52b77\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;drop_cap&quot;:&quot;yes&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Das Herzst\u00fcck meines Dokumentenmanagement-Systems hat sich erst im Nachhinein entwickelt. Am Anfang ging ich eigentlich stark davon aus, dass das Herzst\u00fcck die Anzeige und Suche von Dokumenten sein wird. Die Aufgabe, f\u00fcr die es auch geschaffen wurde.<\/p><p>Etwas sp\u00e4ter stellte sich aber heraus, dass das Herzst\u00fcck die Automatisierung sein w\u00fcrde.<\/p><p>Der Upload von Dokumenten \u00fcber das Webinterface klappte ja soweit gut. Ich wollte es aber irgendwann noch einfacher haben. Daher \u00fcberlegte ich mir, wie die einzelnen Schritte aussehen, wenn ich einen Brief oder ein Dokument ablegen m\u00f6chte:<\/p><p>Ich bekomme ein Brief, den ich im DMS ablegen m\u00f6chte. Sobald er hier bei uns im Flur liegt, \u00f6ffne ich ihn, lese ihn, scanne ihn ein, \u00fcbertrage ihn auf meinen Laptop und lade ihn dort hoch.<\/p><p>Insbesondere die letzten drei Schritte haben immer noch ein wenig \u00dcberwindung und Zeit gekostet. Aber was habe ich daran \u00e4ndern k\u00f6nnen?<\/p><p>Ganz einfach: Meine Drucker- \/ Scannerkombination (damals ein Brother MFC; heute ein Epson Workforce Ger\u00e4t) beherrschten beide das Scannen eines Dokuments und dem automatischen Versand per E-Mail an eine Adresse.<\/p><p>Hier sah ich meine M\u00f6glichkeit, mir die l\u00e4stigen Schritte des Speicherns und manuellen Hochladens abzunehmen: Der Scanner schickt mir die PDF einfach direkt an mein System und dieses macht dann mittels Magie aus der E-Mail mit Anhang ein neues Dokument in meinem DMS.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-37ecaa8 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"37ecaa8\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-96eaef9\" data-id=\"96eaef9\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-aa835bd elementor-drop-cap-yes elementor-drop-cap-view-default elementor-widget elementor-widget-text-editor\" data-id=\"aa835bd\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;drop_cap&quot;:&quot;yes&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Prima, da hatten wir die n\u00e4chste Baustelle. Auch hier \u00fcberlegte ich: Was muss es wie oder wann machen und welche Aufgaben soll es am Ende erf\u00fcllen.<\/p><p>Daraus entstanden ist eine PHP Anwendung, welche per Cronjob auf meinem Server alle f\u00fcnf Minuten gestartet wurde. Normalerweise verwendet man PHP um z.B. Inhalte von Webseiten dynamisch darstellen oder generieren zu lassen. In dem Fall sollte das ganze nur intern ablaufen und keine Ausgaben erzeugen. (OK, streng genommen erzeugt es doch ausgaben, aber auf Konsolenebene um ein Log zu schreiben.)<\/p><p>Also, was musste es machen:<\/p><ul><li>In einem E-Mailpostfach E-nach neuen E-Mails sehen<\/li><li>E-Mails auswerten und E-Mails mit einem PDF als Anhang einlesen<\/li><li>Diese PDF dann einem Benutzer zuordnen und als neues Dokument ablegen<\/li><\/ul><p>Mittlerweile habe ich das ganze noch erweitert:<\/p><ul><li>OCR Texterkennung<\/li><li>Versenden von Best\u00e4tigungsemails an die Benutzer<\/li><li>Ausf\u00fchrliches Logging der einzelnen Schritte<\/li><li>Selbstreparatur, falls das Skript einmal abgebrochen ist<\/li><\/ul>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-502d522 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"502d522\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b7fd44e\" data-id=\"b7fd44e\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-55d54ee elementor-drop-cap-yes elementor-drop-cap-view-default elementor-widget elementor-widget-text-editor\" data-id=\"55d54ee\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;drop_cap&quot;:&quot;yes&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Aber beginnen wir am Anfang. Mein \u201eFetchmail\u201c getauftes Skript (ein wenig angelehnt an das gleichnamige Programm fetchmail) baut als ersten Schritt eine IMAP Verbindung zu einem Postfach auf, wo dann die E-Mails mit PDF Anhang warten:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-f0b1c0b elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"f0b1c0b\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-59691f1\" data-id=\"59691f1\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1077c42 elementor-widget elementor-widget-code-block-for-elementor\" data-id=\"1077c42\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-block-for-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre class='line-numbers theme-okaidia' data-show-toolbar='yes'><code class='language-php'>$imap = imap_open(&#039;{&#039; . $config[&#039;smtpHost&#039;] . &#039;:993\/imap\/ssl}INBOX&#039;, $config[&#039;smtpLogin&#039;], $config[&#039;smtpPassword&#039;]) or die(date(&quot;Y-m-d H:i:s&quot;) .&quot; &quot;. $randomString .&quot; [ERROR] IMAP Verbindung fehlgeschlagen\\n&quot;);\n$message_count = imap_num_msg($imap);\nfor ($m = 1; $m &lt;= $message_count; ++$m) {\n    $header = imap_header($imap, $m);\n    $body = imap_fetchbody($imap, $m, 1);\n    $message_count; ++$m) {\n    $email[$m][&#039;from&#039;] = $header-&gt;from[0]-&gt;mailbox . &#039;@&#039; . $header-&gt;from[0]-&gt;host;\n    $email[$m][&#039;fromaddress&#039;] = @$header-&gt;from[0]-&gt;personal;\n    $email[$m][&#039;to&#039;] = $header-&gt;to[0]-&gt;mailbox;\n    $email[$m][&#039;subject&#039;] = $header-&gt;subject;\n    $email[$m][&#039;message_id&#039;] = $header-&gt;message_id;\n    $email[$m][&#039;date&#039;] = $header-&gt;udate;\n    ...\n}\n<\/code><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-4eefac0 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"4eefac0\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d0f289b\" data-id=\"d0f289b\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-94e43a3 elementor-widget elementor-widget-text-editor\" data-id=\"94e43a3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Was passiert hier? In der Zeile 1 wird die IMAP Verbindung aufgebaut. Die Variablen im Quelltext sind in einer separaten Konfigurationsdatei gespeichert. Sollte die IMAP Verbindung nicht klappen, wird das ganze Skript beendet und es gibt eine R\u00fcckmeldung (die dann im Log landet).<\/p><p>Nachdem die IMAP Verbindung aufgebaut wurde, wird in der Zeile 2 die Anzahl der E-Mails gez\u00e4hlt.<\/p><p>Zeile 3 f\u00fchrt eine Schleife durch und z\u00e4hlt dabei die Durchl\u00e4ufe und vergleicht diese mit der der Anzahl der E-Mails. Ist das maximum erreicht, steigt das Skript aus der Schleife aus.<\/p><p>Zeile 4 und 5 \u00a0legen alle IMAP Daten in eine bzw. zwei Variablen, auf die ich dann danach zugreifen kann.<br \/>Zum Beispiel findet man die meisten Metadaten einer E-Mail im Header, so erfahre ich z.B. \u201eWo kommt die Mail her?\u201c oder \u201eWo soll die Mail hin?\u201c. Damit das ganze etwas \u00fcbersichtlicher wirkt, wandert alles in eine Variable $email die jeweils einen Index mit der zuvor durchgez\u00e4hlten E-Mail erh\u00e4lt.<\/p><p>Dadurch kann ich sp\u00e4ter jederzeit auf die E-Mails zugreifen (innerhalb des Skriptes).<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-11fff71 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"11fff71\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0cf89d8\" data-id=\"0cf89d8\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-812b6a0 elementor-widget elementor-widget-code-block-for-elementor\" data-id=\"812b6a0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-block-for-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre class='line-numbers theme-okaidia' data-show-toolbar='yes'><code class='language-php'>$structure = imap_fetchstructure($imap, $m);\n$attachments = array();\n\nif (isset($structure-&gt;parts) &amp;&amp; count($structure-&gt;parts)) {\n    for ($i = 0; $i &lt; count($structure-&gt;parts); $i++) {\n        $attachments[$i] = array(\n            &#039;is_attachment&#039; =&gt; false,\n            &#039;filename&#039; =&gt; &#039;&#039;,\n            &#039;name&#039; =&gt; &#039;&#039;,\n            &#039;attachment&#039; =&gt; &#039;&#039;\n        );\n\n        if ($structure-&gt;parts[$i]-&gt;ifdparameters) {\n            foreach ($structure-&gt;parts[$i]-&gt;dparameters as $object) {\n                if (strtolower($object-&gt;attribute) == &#039;filename&#039;) {\n                    $attachments[$i][&#039;is_attachment&#039;] = true;\n                    $attachments[$i][&#039;filename&#039;] = $object-&gt;value;\n                }\n            }\n        }\n\n        if ($structure-&gt;parts[$i]-&gt;ifparameters) {\n            foreach ($structure-&gt;parts[$i]-&gt;parameters as $object) {\n                if (strtolower($object-&gt;attribute) == &#039;name&#039;) {\n                    $attachments[$i][&#039;is_attachment&#039;] = true;\n                    $attachments[$i][&#039;name&#039;] = $object-&gt;value;\n                }\n            }\n        }\n\n        if ($attachments[$i][&#039;is_attachment&#039;]) {\n            echo date(&quot;Y-m-d H:i:s&quot;) .&quot; &quot;. $randomString .&quot; [INFO] E-Mail Anhang vorhanden MailCountID: &quot;. $m .&quot; MessageID: &quot;. $header-&gt;message_id .&quot;\\n&quot;;\n            $attachments[$i][&#039;attachment&#039;] = imap_fetchbody($imap, $m, $i + 1);\n            if ($structure-&gt;parts[$i]-&gt;encoding == 3) { \/\/ 3 = BASE64\n                $attachments[$i][&#039;attachment&#039;] = base64_decode($attachments[$i][&#039;attachment&#039;]);\n            } elseif ($structure-&gt;parts[$i]-&gt;encoding == 4) { \/\/ 4 = QUOTED-PRINTABLE\n                $attachments[$i][&#039;attachment&#039;] = quoted_printable_decode($attachments[$i][&#039;attachment&#039;]);\n            }\n        }else{\n            echo date(&quot;Y-m-d H:i:s&quot;) .&quot; &quot;. $randomString .&quot; [WARNING] Kein E-Mail Anhang vorhanden MailCountID: &quot;. $m .&quot; MessageID: &quot;. $header-&gt;message_id .&quot;\\n&quot;;\n        }\n    }\n}\t\t\t\t\t\t\t<\/code><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-5a35ebf elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"5a35ebf\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-113a0d5\" data-id=\"113a0d5\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-d025ea6 elementor-widget elementor-widget-text-editor\" data-id=\"d025ea6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Hier passiert folgendes: Es wird geschaut ob Anh\u00e4nge in der E-Mail vorhanden sind. Es wird sozusagen die Gesamte Mailstruktur in die Variable $attachments gespeichert.\u00a0<\/p><p>Diese kann ich unter anderem darauf pr\u00fcfen, ob ein Anhang vorhanden ist. Das passiert in der letzten IF-Struktur, in der auch gleichzeitig gepr\u00fcft wird wie der Anhang kodiert ist. Denn: Je nach genutztem Standard, kann der Anhang unterschiedlich kodiert sein. Es ist z.B. auch m\u00f6glich, dass der Anhang gar kein Anhang an sich ist, sondern die Datei im Base64 Format in der E-Mail geschrieben steht (sogenanntes Inline). Die E-Mailprogramme selbst machen daraus dann aber wieder ein \u201eanklickbaren\u201c Anhang wie man es kennt.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-2e3776f elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"2e3776f\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0e2518a\" data-id=\"0e2518a\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6422ed9 elementor-widget elementor-widget-text-editor\" data-id=\"6422ed9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<blockquote><p><em><span style=\"color: #0000ff;\">Kurze Anmerkung an dieser Stelle: Ich habe bisher noch nicht alle erdenklich und m\u00f6glichen Szenarien abgedeckt. Ich habe mich daher dazu entschlossen, das Skript nach Bedarf zu erweitern oder anzupassen, wenn z.B. ein E-Mailanhang nicht erkannt oder richtig verarbeitet wird. Da es sich eben um ein privates Projekt handelt, musste ich hier nicht auf alle Eventualit\u00e4ten R\u00fccksicht nehmen :).<\/span><\/em><\/p><\/blockquote>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-8ac25de elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"8ac25de\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ca35382\" data-id=\"ca35382\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-2b84d36 elementor-drop-cap-yes elementor-drop-cap-view-default elementor-widget elementor-widget-text-editor\" data-id=\"2b84d36\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;drop_cap&quot;:&quot;yes&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>So, jetzt habe ich die E-Mails also im System und das Skript geht die E-Mails nach und nach durch und schaut ob Anh\u00e4nge vorhanden sind. Nun musst mit den E-Mails aber noch etwas passieren.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-bc31626 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"bc31626\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-845c32f\" data-id=\"845c32f\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-9451670 elementor-widget elementor-widget-code-block-for-elementor\" data-id=\"9451670\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-block-for-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre class='line-numbers theme-okaidia' data-show-toolbar='yes'><code class='language-php'>$attName = utf8_decode(imap_utf8($attachment[&#039;filename&#039;]));\n$attPdfaName = $attName .&quot;.pdfa&quot;;\n$contents = $attachment[&#039;attachment&#039;];\n$contentsB64 = base64_encode($attachment[&#039;attachment&#039;]);\n\n$isattachment = $attachment[&#039;is_attachment&#039;];\necho date(&quot;Y-m-d H:i:s&quot;) .&quot; &quot;. $randomString .&quot; [INFO] Speichere Anhang tempor&auml;r ab: &quot;. $config[&#039;fetchmailRoot&#039;].&quot;uploads\/&quot; . $attName.&quot;\\n&quot;;\nfile_put_contents($config[&#039;fetchmailRoot&#039;].&quot;uploads\/&quot; . $attName, $contents);<\/code><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-f91e3e0 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"f91e3e0\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-8fe9301\" data-id=\"8fe9301\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-954954b elementor-widget elementor-widget-text-editor\" data-id=\"954954b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Hier lege ich den zuvor erkannten Anhang in einen tempor\u00e4ren Ordner (ja, direkt ins Filesystem &#8211; ganz ohne komme ich dann doch nicht aus &#8211; aber ist ja nur kurzfristig ;D).<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-135e708 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"135e708\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-21261ff\" data-id=\"21261ff\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-4b927c4 elementor-widget elementor-widget-code-block-for-elementor\" data-id=\"4b927c4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-block-for-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre class='line-numbers theme-okaidia' data-show-toolbar='yes'><code class='language-php'>$shellexec = shell_exec(&quot;ocrmypdf -l deu+eng --force-ocr --output-type pdfa &quot;. $config[&#039;fetchmailRoot&#039;].&quot;uploads\/&quot;. $attName .&quot; &quot;. $config[&#039;fetchmailRoot&#039;] .&quot;uploads\/&quot;. $attPdfaName .&quot; 2&gt;&amp;1&quot;);\n<\/code><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-eba6824 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"eba6824\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-18ed4a4\" data-id=\"18ed4a4\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-c857e7b elementor-widget elementor-widget-text-editor\" data-id=\"c857e7b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Hier passiert nun die Magie der Texterkennung. Ich nutze daf\u00fcr ein Programm unter Linux und rufe es mittels shell_exec (diese Funktion kann man verwenden um einen Befehl auf der Shell auszuf\u00fchren) auf und lasse aus dem starren PDF ein PDF\/A inklusive Textlayer generieren. Das Ziel-PDF bekommt dann noch die Dateiendung .pdfa (Dateiendungen unter Linux sind \u00fcbrigens nur reine Kosmetik f\u00fcr uns Menschen).<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-252a591 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"252a591\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-853c95b\" data-id=\"853c95b\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-f75ea4b elementor-widget elementor-widget-code-block-for-elementor\" data-id=\"f75ea4b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-block-for-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<pre class='line-numbers theme-okaidia' data-show-toolbar='yes'><code class='language-php'>$pdfaFile = file_get_contents($config[&#039;fetchmailRoot&#039;].&quot;uploads\/&quot;. $attPdfaName);\n$pdfaFile = base64_encode($pdfaFile);\n$parser = new \\Smalot\\PdfParser\\Parser();\n$pdfGetText    = $parser-&gt;parseFile($config[&#039;fetchmailRoot&#039;].&quot;uploads\/&quot;. $attPdfaName);\n$documentIndex = $pdfGetText-&gt;getText();<\/code><\/pre>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-9bdc460 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"9bdc460\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-096f5db\" data-id=\"096f5db\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-708acb7 elementor-widget elementor-widget-text-editor\" data-id=\"708acb7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Der neu erzeugte Textlayer wird mit einer Klasse von\u00a0<a href=\"https:\/\/pdfparser.org\">PDF Parser<\/a>\u00a0(vielen Dank f\u00fcr diese tolle PHP Klasse!) extrahiert und schlussendlich in eine Variable ($documentIndex) abgelegt. In dieser Variable befindet sich nun alles an Text, was ocrmypdf vorher erkannt hat.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-c1983b6 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"c1983b6\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-600bbfa\" data-id=\"600bbfa\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-cf3c2b2 elementor-widget elementor-widget-text-editor\" data-id=\"cf3c2b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<blockquote><p><span style=\"color: #0000ff;\">\u00dcbrigens: Texterkennung ist grunds\u00e4tzlich immer eine Sache f\u00fcr sich. Die Texterkennung ist allgemein nur so gut, wie das eingescannte PDF. \u00a0Texterkennung funktioniert in der Regel \u00fcber eine Matrix, sprich es werden erst die Unterschiede der unterschiedlichen Pixel digitalisiert und dann werden diese \u201ePixelgebilde\u201c mit einer Matrix verglichen um daraus Buchstaben zu bilden.\u00a0<\/span><\/p><p><span style=\"color: #0000ff;\">Tesseract ist eine kostenfreie Anwendung, die f\u00fcr den allgemeinen Gebrauch recht gute Dienste liefert. Ich habe aber auch immer mal wieder Dokumente, da ist die Erkennung komplett unbrauchbar oder es werden nur wenige Worte erkannt. F\u00fcr mich ist das eine Einschr\u00e4nkung mit der ich Leben kann. Alles in Allem habe ich aber durchweg gute Ergebnisse.<\/span><\/p><\/blockquote>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-b02a35e elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"b02a35e\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-41a47d9\" data-id=\"41a47d9\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-5f1035d elementor-widget elementor-widget-text-editor\" data-id=\"5f1035d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Und nun? Was machen wir nun mit den gewonnenen Informationen? Ich lege Sie mit in die Datenbank. Sie werden sp\u00e4ter mit in die Tabelle aufgenommen, die Spalte der Tabelle aber versteckt (Danke geht an Datatables!). Dadurch flie\u00dfen diese Daten mit in die Tabelle ein, die dann wiederum durchsucht werden kann.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-51c7e8b elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"51c7e8b\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-de3cc69\" data-id=\"de3cc69\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-ee56071 elementor-widget elementor-widget-text-editor\" data-id=\"ee56071\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Fortsetzung folgt&#8230;<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Das Herzst\u00fcck meines Dokumentenmanagement-Systems hat sich erst im Nachhinein entwickelt. Am Anfang ging ich eigentlich stark davon aus, dass das Herzst\u00fcck die Anzeige und Suche von Dokumenten sein wird. Die Aufgabe, f\u00fcr die es auch geschaffen wurde. Etwas sp\u00e4ter stellte sich aber heraus, dass das Herzst\u00fcck die Automatisierung sein w\u00fcrde.<\/p>\n","protected":false},"author":1,"featured_media":936,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_eb_attr":"","_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[18,17],"tags":[],"class_list":["post-644","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dokumentenmanagement-selbst-gemacht","category-server-programmierung-co"],"_links":{"self":[{"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/posts\/644","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/comments?post=644"}],"version-history":[{"count":5,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/posts\/644\/revisions"}],"predecessor-version":[{"id":937,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/posts\/644\/revisions\/937"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/media\/936"}],"wp:attachment":[{"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/media?parent=644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/categories?post=644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/tags?post=644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}