[PHP] Text richtig kürzen. Nach dem Wort, nicht mittendrin.

Hallo,

hier mal wieder ein Codeschnipsel den ich selbst des Öfteren brauche.

Ab und an muss man mit PHP ja mal einen Text kürzen. Zum Beispiel um eine kleine Vorschau des Textes in einer Kategorie anzuzeigen oder auf sonst einer Übersichtsseite.

Nun könnte man mit substr() den Text einfach nach der vorgegebenen Anzahl an Zeichen abschneiden und 3 Punkte dahinter setzen. Leider passiert dann in den meisten Fällen folgendes:

Hallo lieber Mann im Mo…

Der Text wird mitten im Wort abgeschnitten. Das sieht bescheiden aus. :( Und die Lösung ist so einfach. Die folgende Zeile schafft einfach Abhilfe. Hier wird der Text nur nach ganzen Wörtern abgeschnitten.

$string = Der Text der abgeschnitten werden soll.
$length = Nach wie vielen Zeichen soll der Text abgeschnitten werden.

$string = preg_replace("/[^ ]*$/", '', substr($string, 0, $length));

[PHP] Einfacher Cache für Webseiten mit PHP

Hallo zusammen,

heute möchte ich mal ein paar Denkanstöße zum Thema Webseite Cachen geben.

Frei übersetzt heißt “cache”: Zwischenspeicher. Und genau das ist es auch. Es wird etwas Zwischengespeichert um etwas schneller zu machen. In diesem Fall die Webseite.
Doch warum Zwischenspeichern? Was bringt das? Hierzu ein kleines Beispiel, welches ich die letzten Tage erfahren durfte.

Ich habe eine Webseite die sich automatisch Inhalte besorgt und in eine Datenbank schreibt. Dazu generiert es automatisch Keywords. Das hat auch alles immer gut geklappt, bis jetzt mein Server ständig in die Knie gegangen ist. Es hat nicht lange gedauert bis ich diese Webseite als den Übeltäter herausgefischt hatte. Dazu muss ich sagen das ich bei der Programmierung ein wenig geschlampt habe. Aber für unser Beispiel ist es optimal.

Also die Webseite ist eine Art Shop. Mit Kategorien und Artikeln. Über 70.000 Artikeln! Und bei jedem Aufruf durch einen Besucher wird die angeforderte Seite generiert. Die Daten werden aus der Datenbank abgefragt und in das Template eingefügt. Dazu gibt es noch Tag-Clouds und ähnliche Artikel. Das sind pro Seite enorme Belastungen für die Datenbank.

Doch schlussendlich sind die einzelnen Seiten immer gleich. Artikel A ist immer Artikel A und die Seite wird daher immer gleich bleiben. Nur die Tags in der Tag-Cloud ändern sich.
Also ist die beste Lösung ein Caching System. Denn mit einem Cache-System wird die Seite einmal generiert und in einem Cache abgelegt. Ruft der nächste Besucher die gleiche Seite noch einmal auf, dann wird die Seite nicht neu erzeugt, sondern aus dem Cache geladen. Das schon die Datenbank und steigert die Performance enorm.

Doch wie funktioniert solch ein Caching System? Eigentlich ganz einfach. Der logische Ablauf ist ja ganz einfach:

Seite muss ja beim ersten Aufruf definitiv generiert werden. Dabei wird der Inhalt im PHP-Cache gehalten und am Ende in eine (Cache)Datei geschrieben und auch ausgegeben. Wird die selbe Seite noch einmal aufgerufen, wird geprüft ob die Cache-Datei vorhanden ist. Wenn ja, dann die Cache-Datei laden und ausgeben. Wenn nicht dann ist es ein “erster Aufruf”.

Soweit die groben Gedanken. Jetzt etwas Detailierter.

Wie ordnen wir denn eine URL einer Datei zu?
Ich habe das mit einem SHA1-Hash gemacht. Damit kann ich eine URL in einen Hash verwandeln, den ich dann als Dateinamen benutze. Somit kann ich einfach prüfen ob eine URL schon gecached ist.

Wird meine Seite jetzt statisch?
Teilweise ja. Aber ein Cache sollte auch mal erneuert werden. Wie oft, das muss jeder individuell entscheiden. Ich Lösche zwischengespeicherte Seiten nach 6 Stunden in der Regel wieder. Warum? Weil sich immer mal etwas ändern kann.
Wie macht man das? Ganz einfach prüfen wann die Cache-Datei erstellt wurde. Wenn Datum länger her ist als 6 Stunden (z.B.) dann die Datei löschen und neu erstellen.

Was ist wenn ich in meiner Seite dynamische Elemente habe?
Ein Cache schaltet grundsätzlich erst einmal alle dynamischen Teile einer Seite aus, da die Seite statisch in eine Datei geschrieben wird. Deswegen muss der Cache auch ab und zu mal wieder gelöscht werden.
Gibt es nun aber Inhalte auf der Seite die bei jedem Aufruf geändert bzw. dynamisch sein sollen, so muss das System so angepasst werden, das dies möglich ist. Zum Beispiel kann man im Template einen Code einbauen, der jedes mal dann ersetzt wird. Wird die Zwischengespeicherte Seite nun ausgelesen so muss der Code vor der Ausgabe ersetzt werden. Das ist gar nicht so schwer wie es sich anhört ;)

Ich werde es am besten mal an ein wenig Code erklären :)

Am Anfang der PHP-Datei (am besten Auslagern oder eine zentrale PHP-Datei haben):

//CACHING Function
// ===================================
define(CACHE_TIME, 43200);
$url = sha1($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
if ((file_exists(ROOT_FOLDER.'cache/'.$url.'.pcae') == true) && (filemtime( ROOT_FOLDER.'cache/'.$url.'.pcae' ) >= ( mktime()-CACHE_TIME ))) {
        //load cache file
        $content = file_get_contents(ROOT_FOLDER.'cache/'.$url.'.pcae');
        include(ROOT_FOLDER.'/funktionen/funktionen/is_chached_functions.php');
        print_r($content);
        exit;
}
elseif ((file_exists(ROOT_FOLDER.'cache/'.$url.'.pcae') == true) && (filemtime( ROOT_FOLDER.'cache/'.$url.'.pcae') < ( mktime()-CACHE_TIME ))) {
        //old cache file, delete
        unlink(ROOT_FOLDER.'cache/'.$url.'.pcae');
}

ob_start();

Und am Ende der Datei (vor jeder Ausgabe):

$content = ob_get_contents();
ob_end_clean();

if (file_exists(ROOT_FOLDER.'cache/'.$url.'.pcae') == true) {
        //delete old cache file
        unlink(ROOT_FOLDER.'cache/'.$url.'.pcae');
}
//Write new cache file
file_put_contents(ROOT_FOLDER.'cache/'.$url.'.pcae', $content);

//functions which shouldn't be cached!
include(ROOT_FOLDER.'/funktionen/funktionen/is_chached_functions.php');
print_r($content);
unset($content);
exit;

Gehen wir das noch einmal Zeile für Zeile durch. Fangen wir oben an.
Ich habe mir hier in CACHE_TIME die Zeit gespeichert, wie oft die Zwischengespeicherte Seite erneuert werden soll. Zeit in Sekunden.
Dann erstelle Ich den SHA1-Hash der aktuellen URL mit Parametern (Wichtig!).
Nun wird geprüft ob die Datei schon existiert und wie alt sie ist. ROOT_FOLDER ist mein Stammverzeichnis auf meinem Server.

Existiert die Datei schon und ist noch nicht veraltet, dann wird der Inhalt geladen. In meiner Datei “is_chached_functions.php” sind Funktionen enthalten die dynamische Inhalte im Template ersetzen. Was ich vorhin kurz angesprochen hatte. Solch ein Inhalt kann im Template mit “<!– UHRZEIT –>” vermerkt sein. In der Funktion würde nun stehen “$content = str_replace(“”<!– UHRZEIT –>”, date(“H:i:s”), $content);”. Damit hätten wir trotz Cache dynamisch die Uhrzeit in die Seite eingefügt.
Und letztendlich wird die Seite ausgegeben.

Existiert die Datei zwar, ist aber veraltet, dann wird sie einfach gelöscht und das Scipt läuft normal weiter und baut die Seite neu auf. Wichtig ist ob_start(). Damit wird angegeben das keine direkte Ausgabe erfolgt, sondern die Seite im PHP Speicher Zwischengespeichert wird.

Der untere Teil:

Hier schreiben wir nun den PHP Zwischenspeicher in die Variable $content und leeren ihn. Dann prüfen wir noch einmal ob die Datei evtl. existiert und löschen sie einfach, falls ja. (Kann ja mal passieren.)
Dann schreiben wir die erzeugte Seite aus $content in die Cache-Datei.
Nicht vergessen auch hier die dynamischen Inhalte zu ersetzen (in unserem Beispiel die Uhrzeit).
Dann noch die Seite ausgeben und fertig. Nun wurde eine neue Cache-Datei erzeugt, die dann beim nächsten Aufruf ausgegeben wird, anstatt die Seite komplett neu aufzubauen.

Der Server wird es danken ;) Der Hoster übrigens auch :) Und der Besucher auch :) Alle werden sich über mehr Performance, weniger Ressourcenverbrauch und schnellere Ladezeiten freuen ;)

Viele Grüße
Gordon

[WordPress] Kommentarlinks einfach mit external, (no)follow und target=_blank

Hallo,

heute mal wieder einen Tipp zu WordPress.

Es ist hart umstritten… Kommentarlinks mit external oder ohne, follow oder nofollow und welchen target soll der Link haben. Die einen sagen Hü, die anderen Hot. Egal, jeder soll machen wie er mag. Doch wie macht man wie man mag?

Eigentlich ganz einfach. Zumindest wenn man alle Kommentarlinks gleich haben will. Also zum Beispiel sollte rel=”external” immer drin stehen, denn schließlich sind die Kommentarlinks external, es sei denn man selbst Kommentiert.

Dazu ruft man einfach seine “functions.php” in einem Editor auf und fügt am Ende, vor “?>” den folgenden Code ein. Natürlich dabei den Linkcode so bearbeiten wie man es mag.

// Kommentarlinks in neuem Tab / Fenster
    function comment_author_link_window() {
	    global $comment;
	    $url = get_comment_author_url();
	    $author = get_comment_author();
	
	    if ( empty( $url ) || 'http://' == $url) {
	    	$return = $author;
    	}
    	elseif(stristr($url, get_home_url())) {
	    	$return = "<a href='".$url."'>".$author."</a>";
    	} else {
	    	$return = "<a href='".$url."' rel='external nofollow' target='_blank'>".$author."</a>";
    	}
	    return $return;
    }
    add_filter('get_comment_author_link', 'comment_author_link_window');

Und schon werden alle Kommentarlinks mit den Attributen versehen die man haben möchte.

Ich persönlich habe alles gesperrt. Also rel=”external nofollow” und auch target=_blank. Viele werden jetzt denken “Was für nen Arsch.”. Aber externe Links sind nunmal “external”. Bei den Kommentaren die ich hier bekomme weiß ich manchmal nicht mehr ob es nur zum Abgreifen eines Links ist oder nicht. Daher “nofollow” und gut. Wer einen Kommentar schreibt, der tut es weil er etwas zu meinem Artikel beitragen möchte und nicht damit seine Seite besser rankt. Und external… ich mag meine Leser und möchte bitte auch das Sie auf meiner Seite bleiben! Finish :)

[vb.net] MDIchild Problem beim ändern der .text-Eigenschaft. Wird in .size nicht übernommen.

Das ist jetzt ein wenig kompliziert zu erklären. Ich bin auch nur darauf gestoßen weil die Software multilingual ist und ich Texte zur Laufzeit ändern muss.

Damit das Problem auftritt muss die Anwendung eine MDI Anwendung sein. Ändern wir nun zur Laufzeit im MDIchild z.B. den Text von Button1 (Me.Button1.Text = „Bla Bla“) dann funktioniert das auch wunderbar. Das Problem dabei ist das sich die Werte von Me.Button1.Size. nicht verändern. Das heißt der Button-Text ändert sich zwar, aber die Size-Eigenschaften nicht.

Das ist insofern ein Problem als das ich ja meist 2 Buttons habe. „Ok“ und „Abbrechen“ oder was auch immer. Nun ändere ich den Text im rechten Button und er wird dadurch kleiner oder größer (autosize = on). Damit das ganze trotzdem weiterhin schick aussieht, muss der linke Button nun so verschoben werden das der Abstand zwischen Button1 und Button2 wieder normal groß ist. Und genau hier brauche ich den neuen Me.Button1.Size.Width-Wert. Der aber immer noch der alte ist.

Die einzige Lösung die ich gefunden habe ist das die Texte der zu ändernden Elemente schon geändert werden müssen noch bevor man in der MDIform das Child öffnet. Dann werden die Werte auch schon beim Laden des Childs geändert. Achso, das Problem ist nicht immer. In der Form-Resize Funktion z.B. ändern sich die Werte ordnungsgemäß. Beim Load allerdings nicht.

Ich denke das Problem werden nur sehr wenige haben, wer ändert schon zur Laufzeit die Texte in Elementen. Aber vielleicht der ein oder andere schon.
Das wäre also eine mögliche Lösung. Hast du noch eine andere, bessere? Dann schreib doch bitte einen Kommentar und zeige uns deine Lösung. Danke.

[VB.NET] Datagridview – Schriftfarbe oder Hintergrundfarbe einer einzelnen Zelle ändern

Problem des Tages heute: Eine einzelne Zelle in einem Datagridview farbig ändern. Egal ob Schriftfarbe oder Hintergrundfarbe.

Schon mal versucht? Geht gar nicht so einfach. Das habe ich auch ganz schnell rausgefunden. Es gibt zwar die Style Eigenschaften, wenn man sich die Zelle mit Me.Datagridview1.Rows(0).Style… vorknöpft. Doch bewirkt eine Änderung hier nicht viel. Erst die letzte bzw. erste neue Zelle wird damit eingefärbt. Nicht aber die Zelle die man eigentlich einfärben möchte.

Und so habe ich heute stundenlang hin und her experimentiert, Google befragt, mich durch etliche Foren belesen, kuriose Klassen ausprobiert… und es am Ende doch selbst gemacht.

Leider ist es ein sehr mühsamer Weg, wenn man einer einzigen besch*** Zelle sagen will “Mache mal den Text Rot!”. Denn man muss das komplette Datagridview manuell anlegen. Ich arbeite ja generell ohne Databindings. Ja, fragt mich nicht warum, ich mache es halt :-) Nur war es bis dato einfach zu sagen Me.Datagridview1.Rows.Add(„Text 1“, „Text 2“, 1, 2, 3, etc.)

Jetzt wird das ganze nicht mehr so einfach. Jetzt müssen wir jede Zelle wirklich einzeln anlegen, denn nur so können wir auf die konkreten Zelleigenschaften zugreifen und auch setzen.
Ok, wie geht es konkret.

Dim DGVRow As New DataGridViewRow 
Dim Cell As DataGridViewCell 

'Eine normale Zelle 
Cell = New DataGridViewTextBoxCell 
Cell.Value = "Ein Text zum Testen" 
DGVRow.Cells.Add(Cell) 

'Eine Zelle mit rotem Text 
Cell = New DataGridViewTextBoxCell 
Cell.Value = "Ein roter Text zum Testen" 
Cell.Style.ForeColor = Color.Red 
DGVRow.Cells.Add(Cell) 

Me.Datagridview1.Rows.Add(DGVRow)

Was machen wir hier? Wir definieren eine einzelne Datagridview-Zelle und weisen dieser alle nötigen Werte zu. Im Normalfall einfach nur den Value. Aber man kann ihr jetzt auch eine Schriftfarbe zuweisen oder eine Hintergrundfarbe, Schriftart und alles weitere.
Dann packen wir die Zelle in einen Datagridview-Row (DGVRow) und können Sie danach neu Formatieren und neu Belegen, mit der nächsten Zelle. Die dann auch wieder in das Row-Element… bis alle Zellen für ein Row voll sind. Das vollständige DGVRow weisen wir letztendlich dem Me.Datagridview.Row.Add zu. Fertig…

… mit einer Zeile. Das müssen wir jetzt für alle Zeilen machen die dem Datagridview hinzugefügt werden sollen. Daher ist meine Empfehlung das ganze einer Funktion zuzuweisen oder noch besser einer Class. Das hier soll ja nur zur Orientierung dienen wie es funktioniert.

Sehr umständlich, aber funktioniert. Und das ohne fremde Klasse. ;-)

Update: Ich korrigiere. Auch mit Me.Datagridview1.Rows(0).Cells(0).Style.ForeColor = … lässt sich die Schriftfarbe verändern. Nur warum es mal funktioniert und mal nicht… das muss ich noch ergründen. Als einfach ausprobieren. Wenn es so funktioniert, dann kann man sich den komplizierteren Weg oben sparen.

Happy Programmers Day!

Hi,

heute mal nur schnell eine Schlagzeile. Was aber nicht heißt das sie unwichtig ist! Denn heute ist Programmers Day (Tag der Programmierer). :-) Ein sehr wichtiger Feiertag (leider kein offizieller… hätte gern frei heute)!

Wer sich jetzt fragt wann denn der Tag der Programmierer im Jahr ist… na ganz einfach… am 256ten Tag im Jahr ;-) Warum 256? Weil man mit einem (8bit) Byte genau 256 verschiede Werte/Zustände (0 und 1) erstellen kann.

Die Zahl ist die Grundzahl eines jeden Programmierers. Wenn ein Programmierer auch sonst nix kann, diese Zahl muss er kennen… sonst ist es kein Programmierer :-)

Ins Leben gerufen wurde der Programmers Day von Valentin Balt im Jahr 2002. Er hat sogar versucht das Russland diesen Tag als offiziellen Feiertag anerkennt. Und?… Seid dem Jahr 2009 gilt der Programmers Day als offizieller Feiertag in Russland. … Ich bin begeistert. :-)

 

Also liebe Programmierer all around the world: Happy Programmers Day!! And less bugs in the next year! ;-)

[VB.NET] NotifyIcon mit Transparenz

Hallo,

heute mal ein kleiner Codeschnipsel zum Thema NotifyIcon mit Transparenz.

Ich habe nicht rausgefunden wie man normal ein *.ico mit Transparenz hinbekommen. Zumindest hat es mein Programm nicht unterstützt. Also habe ich mir einen kleinen Code gebastelt der ein bisschen rumtrickst. :-) Damit kann man auch noch sicher andere Sachen basteln.

Funktionieren tut es ganz einfach. In meinem Fall habe ich eine ImageList die diverse Bilder beinhaltet. Daraus suche ich einfach eines raus und lasse es als NotifyIcon setzen.

Die Sub dazu sieht dann so aus. Muss natürlich noch mit dem Programmstart ausgeführt werden.

' sets a new icon from the imagelist. because of the transparens
    Sub createNotifyIcon()
        Try
            Dim img As Bitmap = Me.ImageList1.Images(1)
            Dim hIcon As IntPtr = img.GetHicon()
            Dim icn As Icon = Drawing.Icon.FromHandle(hIcon)
            Me.NotifyIcon1.Icon = icn
            icn = Nothing
            hIcon = Nothing
            img = Nothing
        Catch exc As Exception
            'ups, error... hope the icon is still there...
        End Try
    End Sub

Ist Technorati wieder zurück? Endlich kann ich wieder eintragen, ohne Connection-Timeout.

Ohh, was ist da los? Ist Technorati wieder zurück? Ist da endlich mal jemand aufgewacht? Neuer Server? Neue Internetleitung? Vorbei die Timout-Zeit?

Unglaublich, aber wahr… ich konnte gerade 3 Seiten Problemlos und ohne 100 Verbindungsunterbrechungen wegen Timeout, bei Technorati eintragen. Ich hatte ja erst vor kurzem darüber geschrieben (siehe Technorati Timout Problem) das es schon seid Monaten nicht mehr möglich ist bei Technorati eine Webseite einzutragen. Einfach weil man es irgendwann leid war das es nach der hundersten Verbindungsunterbrechung, weil der Server von Technorati beim Eintragen (und nur da), einen Timeout hatte, wieder auf “Noch mal versuchen” zu klicken.

Und jetzt scheint es auf einmal wieder zu gehen! Oder ist das nur ein Zeitfenster und ich habe gerade Glück?? Keine Ahnung, aber falls dem so ist… tragt schnell eure Seiten ein, solange es möglich ist!!! ;-)

Auch die Mails mit dem Verifizierungscode kamen sofort an. Ich hoffe die werden auch schnell gecheckt… bevor das Glück wieder vorbei ist. *bibber*

Bug in WordPress XMLRPC wp.uploadfile – Dateiupload funktioniert nicht!

Gerade habe ich einen Bug in der XMLRPC-Schnittstelle von WordPress gefunden. Anscheinen nutzt diese Funktion aber wohl kaum jemand, wenn es noch keinem Aufgefallen ist. Ich habe aber genau diese Klasse kopiert und in einem anderen Projekt verwendet, um es mir mal einfacher zu machen. :-)

Der Bug befindet sich in der wp.uploadFile aka mw_newMediaObject Funktion. Mit dieser Funktion können Dateien über die XMLRPC-Schnittstelle in den Blog geladen werden.
Das Problem, es funktioniert nur nicht wirklich. Die Daten müssen per base64_encode codiert werden. Hab ich auch brav gemacht, nur werden sie im Blog nicht wieder decodiert und damit genau so gespeichert wie sie übertragen werden. Das kann jedoch nicht funktionieren.

Also habe ich mich auf die Suche gemacht und den Fehler gefunden. Die XMLRPC Klasse von WordPress (class-IXR.php) erkennt auf der Client-Seite Base64-Codierte Strings nicht. Ich habe im Netz auch keine Möglichkeit gefunden wie man prüfen kann ob ein String im Base64-Format vorliegt. Daher habe ich zu einer anderen Möglichkeit gegriffen den Bug zu fixen.

Wir gehen mal wieder in den Code. Achtung: Wenn diese Änderung im Blog selbst vorgenommen wird, wird es beim nächsten Update überschrieben!
Als erstes nehmen wir uns ca. Zeile 35 vor. Hier sollte folgendes stehen:

foreach ($this->data as $key => $value) {
     $this->data[$key] = new IXR_Value($value);
}

Das ändern wir in:

foreach ($this->data as $key => $value) {
     if($key == "bits") $this->data[$key] = new IXR_Value($value, "base64");
     else $this->data[$key] = new IXR_Value($value);
}

Soweit ich gesehen habe gibt es den “bits” Parameter nur ein mal in der Schnittstelle. Und zwar genau dort wo der Base64-String unserer Datei drin ist. Also sagen wir “Wenn Parameter ‚bits’ ist, dann ist es Base64. Und schon schalten wir die automatische – und falsche – Erkennung des Variablen-Types aus und sagen gleich das es Base64 ist.

Dann gehen wir noch zu einem anderen Bug. Der ist ca. in Zeile 114. Die Originalzeile heißt:

case 'date':
     case 'base64':
          return $this->data->getXml();
          break;

Das gibt einen Fehler. Die Funktion getXml() gibt es unter $this->data nicht und wäre auch Schwachsinn.  Die Zeilen müssen wie folgt aussehen:

case 'date':
          return $this->data->getXml();
          break;
     case 'base64':
          return '<base64>'.$this->data.'</base64>';
          break;

So, jetzt sollte es funktionieren.

Wie gesagt, wenn ihr die Klasse kopiert habt und in einem anderen Projekt verwendet, dann ist es ok. Wenn ihr es im WordPress selbst ändert dann wird es beim nächsten Update überschrieben.

[WordPress] FTP Daten für automatische Updates festlesen

Da wir heute gerade schon mal beim Thema waren. Hier gleich noch ein Beitrag zu den automatischen Updates. Normalerweise fragt WordPress immer nach den FTP Daten um die Updates zu installieren. Man kann diese jedoch auch in der wp-config.php selbst (und fest) vorgeben. Dann müssen sie einerseits nicht mehr ständig eingegeben werden und es verringert auch das Sicherheitsrisiko (sagen jedenfalls die Experten :-) ).

Also wp-config.php öffnen und irgendwo – am besten nach den SQL Daten – die folgenden Parameter eintragen (und konfigurieren natürlich).

define('FTP_HOST', 'musterdomain.de');
define('FTP_USER', 'ftp_user');
define('FTP_PASS', 'ftp_paswort');

Die folgenden Zeilen müssen nicht angegeben werden. Wenn Du weißt was Du tust, dann kannst Du auch hier eigene Einstellungen vornehmen.

define('FTP_SSL', true); //SSL Verschlüsselter Upload
define('FTP_BASE', '...'); //Root Verzeichnis der WordPress Installation
define('FTP_CONTENT_DIR', '...'); //wp-content Verzeichnis
define('FTP_PLUGIN_DIR', '...'); //wp-plugin Verzeichnis
define('FS_METHOD', 'direct'); //FTP Methode