Programmierung
Sequentielle Suche mit FileMaker und PHP
Manchmal sind es nicht die großen Frameworks oder hochkomplexen API-Integrationen, die den Unterschied machen, sondern ein bewusst einfacher, robuster Ansatz, der sich nahtlos in vorhandene Workflows integriert. Genau das war der Ausgangspunkt für eine kleine aber wirkungsvolle Lösung, die FileMaker mit einem PHP-basierten Webinterface verbindet – mit dem Ziel, eine sequentielle Suche über eine größere Datenmenge performant und flexibel umzusetzen.
Das derzeitige Problem beim Kunden, vor Jahren habe ich eine Sequentielle Suche nativ in FileMaker umgesetzt. Die übliche Vorgehensweise, ein Script sucht bei jedem Tastenanschlag, genutzt werden alle Felder die in der Schnellsuche eingeschlossen sind. Über die Jahre wuchs der Datenbestand, es wurden Felder innerhalb von Ausschnitten erfasst. Es musste so kommen, der Kunde konnte die Suche kaum mehr nutzen, tippen, warten, tippen. Sehr unschön und langsam.
Dann kam mir im Zuge einer Listenansicht, in die ich eine Suche integriert habe, die Idee. FileMaker überträgt per -Aus URL einfügen- Tabellendaten an ein PHP-Script. Im WebViewer wird dann die Tabelle angezeigt, nebst einem Suchfeld. Also frisch ans Werk gemacht und schnell festgestellt, die Felder in Variablen zu verpacken, macht in der Menge keinen Spaß. Also das ganze per Schleife, Feldnamen holen, die Werte dazu sammeln. In Schleife, ist das gut machbar, aber trotzdem ein nicht unerheblicher Zeitaufwand. Dann eine Eingebung, exportiere die Tabelle und verarbeite die Daten direkt auf dem Server per PHP.

Vorgehen: FileMaker exportiert eine strukturierte Datenmenge als CSV – diese Datei wird im Hintergrund automatisch an ein kleines PHP-Script übermittelt. Dort wird sie interpretiert, analysiert und in einer visuellen Oberfläche dargestellt, über die eine freie Volltextsuche möglich ist. Der Clou: Mit jedem Tastendruck wird die Ergebnisliste dynamisch reduziert – und bei Bedarf lassen sich über die Enter-Taste direkt Projektnummern an ein FileMaker-Script zurückgeben, das dann wiederum die interne Detailansicht aktualisiert. Ganz ohne Datenbankabfragen im Webserver, ganz ohne MySQL, Redis oder externe Services.
Die PHP-Logik bleibt dabei angenehm überschaubar. Ein Beispiel für das Parsen und Darstellen der Daten sieht so aus:
<?php $csvData = []; $data = file_get_contents("php://input"); if ($data && strlen($data) > 0) { $lines = preg_split('/\r\n|\r|\n/', $data); foreach ($lines as $line) { if (trim($line) !== "") { $csvData[] = str_getcsv($line, "\t"); // Tab-getrennt } } if (!empty($csvData) && empty(array_filter(end($csvData)))) { array_pop($csvData); } } $spaltenIndizes = range(0, count($csvData[0] ?? []) - 1); ?>
In der Darstellung im WebViewer werden alle Datensätze tabellarisch angezeigt. Der Clou kommt mit JavaScript: Dort wird bei jeder Eingabe automatisch geprüft, welche Zeilen noch zum aktuellen Suchbegriff passen. Zusätzlich hebt ein kleiner Style-Block die passenden Zellen farblich hervor, um die Treffer visuell zu unterstützen. Und weil alles clientseitig passiert, bleibt es schnell – auch bei mehreren tausend Einträgen.
Besonders elegant wirkt die Integration in FileMaker: Die Projektnummern der sichtbaren Zeilen werden bei einem Enter-Klick gesammelt und per fmp://-URL an ein FileMaker-Script übergeben. Diese Direktverbindung ermöglicht, das Webinterface wie eine native Erweiterung der Datenbank zu nutzen – ohne Performanceverlust, ohne Redundanz, ohne Hürden.
document.getElementById("searchInput").addEventListener("keypress", function(event) { if (event.key === "Enter") { event.preventDefault(); const rows = document.querySelectorAll("#csvTable tbody tr:not(.hide)"); const ids = []; rows.forEach(row => { const id = row.querySelectorAll("td")[0]?.textContent.trim(); // Erste Spalte = ID if (id) ids.push(id); }); if (ids.length > 0) { const param = encodeURIComponent(ids.join("|")); const url = `fmp://$/AVAGmbH?script=Projekt_LIST_Suche_PHP¶m=${param}`; window.location.href = url; } } });
Nach dem Klick, startet das FM-Script. Wir holen uns die ID,s nach üblicher Vorgangsweise und suchen in Schleife alle ID,s zusammen. In dem Zug, wird natürlich auch das Suchfenster in FileMaker geschlossen.

Diese Form der sequentiellen Suche hat sich im Test als stabil und pflegeleicht erwiesen – gerade in Szenarien, in denen FileMaker allein bei umfangreichen Datensätzen an die Grenzen kommt, etwa bei mehrdimensionalen Suchen über unstrukturierte Felder oder bei extern generierten Listen.
Und auch wenn es kein High-End-AI-Suchcluster ist: Die Lösung hat Charme. Weil sie genau das tut, was sie soll. Weil sie den Workflow nicht verbiegt, sondern erweitert. Und weil sie etwas bietet, das man oft zu selten hat: unmittelbare Rückmeldung und Kontrolle über den gesamten Prozess.
Jetzt wird nur noch ein wenig mit CSS das ganze verschönt, dann kann der Kunde damit arbeiten.
Grundlegende Fehler bei der Nutzung von Formeln in FileMaker – und wie man sie vermeidet
Grundlegende Fehler bei der Nutzung von Formeln in FileMaker – und wie man sie vermeidet
Formeln sind in FileMaker ein mächtiges Werkzeug, das eine Vielzahl von Funktionen und Berechnungen ermöglicht. Doch die unsachgemäße Nutzung von Formeln kann schnell zu erheblichen Performance-Problemen und schwer zu wartenden Datenbanklösungen führen. Heute will ich diese Problematik einmal beleuchten.
- Ungespeicherte Berechnungen überstrapazieren
Eine ungespeicherte Berechnung wird jedes Mal neu berechnet, wenn ein Datensatz angezeigt oder referenziert wird. Das bedeutet, dass komplexe Berechnungen in großen Tabellen die Leistung massiv beeinträchtigen können.
Beispiel:
Eine Formel wie Sum(Bestellungen::Betrag) wird jedes Mal neu berechnet, wenn der Kunde angezeigt wird.
Lösung: • Verwende gespeicherte Felder, wenn die Werte sich nicht ständig ändern. • Nutze Skripte, um Berechnungsergebnisse in einem statischen Feld zu speichern, das nur bei Bedarf aktualisiert wird.
- Verschachtelte und komplexe Formeln
Lange verschachtelte Formeln können schwer zu lesen, zu warten und vor allem langsam sein. FileMaker muss jeden Teil einer komplexen Formel bei jeder Neuberechnung analysieren.
Beispiel:
If( Rechnungen::Status = “Bezahlt”; Rechnungen::Summe * 0.19; If(Rechnungen::Status = “Offen”; Rechnungen::Summe * 0.25; 0) )
Lösung: • Teile komplexe Formeln in mehrere einfache Schritte auf. • Verwende Hilfsfelder oder Skripte, um Zwischenberechnungen durchzuführen. Zumal in diesem Beispiel eine einfache Formel, im deutschen FileMaker setzeVar(), häufig die Beste Lösung ist. Gerade Anfänger scheuen sich aber diese zu verwenden weil, diese unübersichtlich erschein. Kleiner Tipp am Rande, ich habe die immer als formatierte Vorlage in meinem Textexpander. Wenn ich das -$var- eintippe, erscheint das: SetzeVar ( [ Var1 = Ausdruck1 ; Var2 = Ausdruck2… ] ; Rechenanweisung ) Einfach sofort zu erkennen was gemeint ist, so ist auch die Nutzung super übersichtlich.
- Dynamische Formeln in Listen und Tabellen
In Layouts, die viele Datensätze gleichzeitig anzeigen (z. B. Tabellenansichten), werden ungespeicherte Formeln für alle angezeigten Datensätze gleichzeitig berechnet. Dies führt zu merklichen Verzögerungen.
Beispiel:
Ein berechnetes Feld zeigt den Namen eines verbundenen Objekts, etwa Bestellungen::Kunden::Name.
Lösung: • Verwende Lookup-Felder, um Werte aus verbundenen Tabellen einmalig zu kopieren. • Zeige in der Tabellenansicht nur unbedingt notwendige Daten an.
- Fehlende Indizes
Indizes sind entscheidend für die Geschwindigkeit von Berechnungen, insbesondere bei Relationen, Suchen und Filtern. Ohne Indizes dauert das Durchsuchen großer Tabellen erheblich länger.
Beispiel:
Ein Beziehungsschlüssel wie _test(Artikel::Name) ist nicht indizierbar.
Lösung: • Verwende indizierbare Felder als Beziehungsschlüssel. • Füge Hilfsfelder hinzu, die den indizierten Wert speichern (z. B. ein zusätzliches Feld NameKlein mit der gespeicherten Formel Lower(Name)).
- Formeln statt Skripte
Oft werden Berechnungen in Formeln realisiert, obwohl Skripte besser geeignet wären. Skripte bieten die Möglichkeit, Berechnungen gezielt auszuführen und Ergebnisse zu speichern, ohne die Performance dauerhaft zu belasten.
Beispiel:
Ein Feld mit der Formel LetzteAktualisierung = Max(Änderungen::Zeitstempel) wird jedes Mal berechnet, wenn der Datensatz angezeigt wird.
Lösung: • Verwende ein Skript, das das Feld bei Änderungen aktualisiert. • Nutze Skript-Trigger, um Werte bei Benutzeraktionen zu berechnen.
- Fehlerhafte Verwendung von globalen Feldern
Globale Felder sind hilfreich, aber oft werden sie für falsche Zwecke eingesetzt, was zu Performance-Problemen führen kann.
Beispiel:
Ein globales Feld wird in einer Beziehung verwendet, um dynamische Filter zu setzen.
Lösung: • Prüfe, ob ein Skript geeigneter ist. • Verwende globale Felder nur für Werte, die sich selten ändern oder systemweit benötigt werden. Häufig nutzte ich diese nur um einen Filter zu setzen. Im allgemeinen machen diese Felder wenig Sinn.
- Übermäßige Nutzung von Aggregatfunktionen
Funktionen wie Sum, Count oder List sind praktisch, können aber bei großen Datenmengen problematisch sein, insbesondere wenn sie über mehrere Relationen hinweg berechnen.
Beispiel:
Sum(Bestellungen::Gesamtbetrag)
Wird für jeden Kunden bei jedem Zugriff neu berechnet.
Lösung: • Nutze Zwischenspeicher, z. B. ein Feld, das bei Änderungen in Bestellungen per Skript aktualisiert wird. • Verwende Statistiktabellen oder Berichte, um Aggregatwerte gezielt zu berechnen. (Aber auch hier ist Vorsicht angebracht, nutze lieber ein PHP Script, baue die Anzeige über ein HTML im WebViewer)
- Übersehen von Feldtypen
Manchmal werden Berechnungen fehlerhaft und dadurch zur echten Bremse, weil der Feldtyp nicht passt – etwa bei der Verarbeitung von Text als Zahl oder umgekehrt.
Lösung: • Stelle sicher, dass die Feldtypen korrekt definiert sind (z. B. Zahlenfelder für numerische Berechnungen).
-
Layoutformel als neues Futures Layoutformeln sind eine echte Erleichterung. Mal schnell einen Wert in einem Layout darstellen, kein Feld, kein Script, keine globale Variable. Aber mit jeder Erleichterung für den Entwickler erkauft man sich ein negativen Punkt. In unserem Fall die Performance.
-
Bedingte Formatierungen in Listenansichten. Ja, wer bis hier gelesen hat, kann sich den Rest denken. Die Liste mit 20000 Datensätzen öffnet sich und FileMaker rechnet jetzt erstmal brav die Bedingungen durch um z.B. einen Farbton eines Symbols zu ändern. Bei kleinen Datenmengen überhaupt kein Problem, aber bei vielen Werten sollte es anders gemacht werden. Wie gehts auch anders? Eine extra Tabelle für Symbole, diese wird je nach Status über eine mit dem Status in Verbindung stehende Referenz verknüpft. Dann halte ich z.B. das Symbol einmal als grünes Symbol vor, einmal als gelbes, einmal als rotes Symbol. Das lässt sich natürlich gewaltig aufblähen, macht viel Arbeit, aber es bringt echten Performance-Schub.
Fazit: Verwende wenig bis keine Formeln Es ist einfach wichtig wenige Formeln zu verwenden. Klar ist der Aufwand für jede Berechnung ein Script zu starten enorm, aber es bringt den Unterschied. Ich habe gerade letztens für ein Unternehmen arbeiten dürfen. Die Datenbank, eine Datenbank mit 20 Jähriger Historie. Die Anforderung des Auftraggebers, Performance-Probleme zu beheben. Aber der Erste Blick in die Tabellen zeigte das ganze Ausmass, 2/3 der Tabellen bestanden aus Formeln. Was will ich da noch retten? Eigentlich ein Fall für die Tonne. Abhilfe konnten teilweise Auslagerungen in Server-Scripts bringen, aber das grundsätzliche Problem konnte nicht behoben werden.
Was sind deine Erfahrungen mit Formeln in FileMaker? Teile deine Gedanken und Tipps in den Kommentaren!
Kreditkartenabrechnung mit FileMaker Teil 2
Nachdem wir im ersten Teil die Grundvoraussetzungen erarbeitet haben gehen wir nun zum eigentlichen Teil innerhalb von FileMaker über.
Für die Anzeige der Daten vom Zahlungs-Dienstleister nutzen wir ein kleines Feld vom Typ WebViewer. Die URL des WebViewers ergibt sich aus dem Pfad zum PHP-Script auf dem Webserver und unseren Parametern die wir aus FileMaker auslesen:
URL.Parameter= “http://www……………………com/Semicon2012/request.php”
&
“?"&“LastName=” & KONTAKT.T_Last_Name & “&” &“Price="&Preis_Heidel_Uebertragung&"&” & “Street=” & KONTAKT.T_Adress & “&” & “Zip=” & KONTAKT.Z_ZIP & “&” & “Stadt=” & KONTAKT.T_City & “&” & “Land=” & KONTAKT.T_Country & “&” & “Mail=” & KONTAKT.T_EMail & “&” & “Buchung=” & INVOICE.BUCHUNG.Nr_1_2 & “&” & “FirstName=” & KONTAKT.T_First_Name&"&” & “Code=” & KONTAKT.SICHERHEIT.CODE
Als Webadresse vergeben wir das Feld URL.Parameter
Rufen wir nun das Layout auf und der WebViewer wird aktiv erscheint die Eingabemaske vom Zahlungs-Dienstleister incl. der eingegeben Parameter wie Zahlungsbetrag, Adresse und anderer Werte.
Nun gibt der Kreditkarteninhaber nur noch seine Kartennummer ein und die Verifikation Number. Nach dem Klick auf Pay Now wird vom Zahlungs-Dienstleister die Zahlung verarbeitet. Im Anschluss wird das PHP-Script “www……………………com/Semicon2012/response.php” aufgerufen.
Das Script ruft je nach Wunsch eine URL auf die dann wieder in unserem WebViewer angezeigt wird.
<?php
//this page is called after the customer finishes
//payment with the Web Payment Frontend.
//It must be hosted YOUR system and accessible
//to the outside world.
//It always must respond with a URL that defines
//which page the WPF should redirect to.
//this new page also MUST be hosted on your system
//AND it musst be accessible so that the WPF can
//redirect the users browser to it.
// PROCESSING.RESULT gets PROCESSING_RESULT when posting back (URL encoding)
$returnvalue=$_POST[‘PROCESSING_RESULT’];
if ($returnvalue)
{
if (strstr($returnvalue,“ACK”))
{
print “Location: http://www…………………………com/Semicon2012/success.html”;
}
else
{
print “http://www……………………………com/Semicon2012/error.html”;
}
}
?>
Wird als Wert ACK vom Zahlungs-Dienstleister an das Script zurückgegeben wird die URL für die erfolge Transaktion aufgerufen. ACK ist immer der Wert für erfolgte Transaktionen.
Nun da wir wissen welcher Wert im WebViewer auftaucht, müssen wir diesen nur noch überprüfen.
Über GetLayoutObjectAttribute(“Webviewer” ; “Source”) können wir den Inhalt des WebViewers abfragen. Vergleichen wir diesen ausgelesenen Inhalt z.B. mit der Funktion Exakt (InhaltWebViewer; Vergleichsfeld) können wir bestimmen ob eine Transaktion erfolgt ist oder nicht.
Mit dieser Methode kann man Kreditkartenlösungen ohne Plugin realisieren.
Dynamische Menüsteuerung Teil 2
Die Tabellen haben wir vorbereitet und arbeiten am Layout weiter. Wir benötigen in unserem Fall innerhalb eines Wunschlayouts ein -Portal- der Tabelle -T18i_timesheet_MENUE||id_constant|
Die Tabelle -T18i_timesheet_MENUE||id_constant| ist eine Instanz der Tabelle MEN_Menue. Dieses ist in meinem Fall die Tabelle des Hauptmenüs. Im Portal finden sich nun die Felder -Menue_Name-, -Menue_Icon-,-Menue_Icon_Rand- und Menue_Icon.
Nach verlassen des Layout-Modus erschein der Button aus dem Feld -Menue_Icon_Rand-, das Symbol aus dem Feld -Menue_Icon- und die Bezeichnung aus dem Feld -Menue_Name-. Das Dynamische Menü ist somit fast fertig. Was fehlt uns? Ein Script zum erkennen der Mausklicks.
Im nächsten und letzten Teil gehe ich auf die Script-Steuerung ein.
Dynamische Menüsteuerung Teil 1



