PHP Problem, Textdatei wird zerstört!

master bratack schrieb:
Achso, was soll den der Zufall jetzt bringen?

Das war Sarkasmus. Aber ist okay, war nicht so leicht zu erkennen ;)

Was ich damit sagen wollte war rein: Wenn ich an die Thematik herangehe und sage, es ist eh egal wenn nur ein paar Sachen gezählt werden, dann brauch ich auch den Aufwand nicht betreiben und kann irgendwas ausgeben.

Ich weiß jetzt zum 10ten mal das ich dafür eine Datenbank nehmen könnte
Es kommt wohl nicht von irgendwoher, dafür eine Datenbank zu verwenden.

Aber wenn du von deiner engstirnigen Sicht weg gehst, permanent keine Datenbanken verwenden zu wollen, finden sich sicher genug Beispiele, die dich auf deinem Weg unterstützen. Man muss das Rad nicht immer neu erfinden, und es hat auch nichts mit leicht aufgeben zu tun, wenn der Weg, den man als Anfänger eingeschlagen hat, falsch ist :)

Ist nett gemeint, jeder war mal Anfänger ;)


so long
Renegade
 
Ich denke mit Flatfiles lernt man erst richtig PHP programmieren ;)
 
Hey!

ich würde es so machen:
Jede ROW deiner "Flatfilebased-DB" entspricht einer einzelnen Datei.
Eine Komplette "Tabelle" existiert somit nicht tatsächlich. Sie kann aber, virtuell durch zusammensätzen einzelner Datensätze (Rows), konstruiert werden.

Die funktion "GetNumRows" liefert die Anzahl der Rows,
Die Funktion SELECT_ALLES wirft ein Array mit allen rows zurück.

Im Bsp. wird durch
$_GET['insert'] eine Neue Row erzeugt
und mit
$_GET['numrows'] die Anzahl der Rows gecastet.


PHP:
<?php
/************************
 * Eine ROW entspricht einer Datei in ./data/
 ***********************/

// zählt die Rows
function GetNumRows() {

$numrows=0;

    foreach(new DirectoryIterator('data') AS $file) {
    
        if(!is_dir($file)) {
        ## $exp_line = explode("|",file_get_contents("/data/".$file));
        $numrows++;
        }
    
    }    
return $numrows;
}

// SELECT * FROM data ;)
function SELECT_ALLES() {
$exp_line = NULL;
foreach(new DirectoryIterator('data') AS $file) {
    
        if(!is_dir($file)) {
        $exp_line[] = explode("|",file_get_contents("data/".$file));
        }
    
    }    
return $exp_line;

}


// Neue Row
if(isset($_GET['insert'])) {
if(!is_dir('data')) { 
mkdir('data',0775);    
}

// Name der Row (also des Flatfile)
$rowname = md5(uniqid());

// Neuer Eintrag (neue Row)
file_put_contents('data/'.$rowname,"11|1|".date("Ymd"));
}

if(isset($_GET['numrows'])) {
echo GetNumRows();    
}


echo "<pre>"; print_r(SELECT_ALLES()); echo "</pre>";

?>
 
Idee (Erleuchtung)
Ab sofort wenn ich mal Hilfe benötige schreibe ich 10 mal...

Diese Sache OHNE DB
Diese Sache OHNE DB
...
und wenn mit dann halt...
Diese Sache MIT DB
Diese Sache MIT DB
...

Ich hoffe dann ist das verständlich genug und der Thread wird nicht kaputt gemacht bzw. komplett zugemüllt mit Sachen mit denen ich absolut nichts anfangen kann.

Es ist nett gemeint nur sind Belehrungen von wegen nur mit DB geht alles usw. nicht das was ich benötige und die helfen mir absolut nicht. Es geht auch ohne DB viel mehr wenn man nur weiß wie, und da liegt wahrscheinlich auch das Problem, das es wohl sehr wenige gibt die wirklich wissen wie es auch ohne geht und immer mit dem Zeigefinger auf DB DB DB zeigen.
So, da dieser Thread jetzt endgültig kaputt ist, denn hier weißt du garnicht mehr wer was meint, ist das mein letzter Beitrag da zwecklos.

Mein Dank geht an die Leute die den DB Finger weggelassen haben und mir beim eigentlichen Problem geholfen haben.
 
mhh, sind doch alles FLAT FIles.

Ich verstehe unter einer Datenbank ein Systen der durchstrukturierten Ablage von Informationen.
Du verstehst unter Datenbank ein fertiges Produkt wie MySql oder Sqlite.

Meine Lösung basiert auf TEXT-Dateien. Kein SQL...
 
Mit den Flatfiles lernt man nicht zu programmieren, man lernt höchstens es ganz fix sein zu lassen.

Du hast da null Abbruchroutinen drin und könntest damit Ghostprozesse provozieren, je nach dem wie der Server eingestellt ist. User brechen gerne den Seitenaufbau ab wenn der Seitenaufruf dank deines FLOCK oder gar wegen der Lockfile-Methode zu lange dauert. Stell dir einfach mal vor, dein Script kann in dem Fall mal NICHT die Datei entsperren oder löschen (im Falle des Lockfile), dann biste aufgeschmissen, zumindest so, wie die Scripte hier geschrieben stehen. Je nach dem, wie viele Besucher du hast, wie lang dein Script maximal vom Server ausgeführt wird und/oder wann du endlich merkst, dass da was nicht stimmt usw kannst du hunderte, tausende von Geisterprozessen erstellen die irgendwann den Server auch crashen lassen können.

Einmal ganz abgesehen davon, dass diese völlig unnötigen Festplattenzugriffe das System verlangsamen, insbesondere, wenn es wachsende Daten sind, was bei dir gottseidank nicht der Fall ist...

Und das ist ein Grund, warum ich nichts davon halte Flatfiles zu nutzen. Denn Flatfiles sind eigentlich dafür da geringfügige Datenmengen aufzunehmen, die entweder selten, oder gar nicht geändert werden müssen und sich somit für diese Speichermethode wirklich KEINE Datenbanken lohnen. Simple Zustände wie an/aus, "wenn das, dann das", ein Cronjob-Flag ("wann wurde der letzte Cronjob getätigt") oder auch ein Cache-File und solche Sachen, dafür ist des in Ordnung. Aber sobald des an Counteraufgaben und Logfiles geht, sind grundsätzlich Datenbanken vorzuziehen.

In jedem Fall solltest du UNBEDINGT eine Abbruchmethode einbauen, die die Scriptlaufzeit auf wenige Sekunden begrenzt, z.B.

PHP:
ini_set("max_execution_time", 10);

falls verfügbar. Ansonsten musst du einen Check einbauen, wo das Script auf gelockte Files mit einem Abbruch reagiert, entweder per sofortigem Abbruch oder Abbruch nach einer vorgegebenen Zeit. Dabei gehen dir allerdings auch entsprechend Zugriffe flöten.

Vielleicht wäre es auch für dich eine gute Idee nicht alles in einer Datei zu speichern, sondern für jeden einzelnen Eintrag der $whitelist eine extra-Textdatei, insbesondere dann Sinnvoll, wenn jeder einzelne Eintrag ähnlich oft geupdated werden muss...

Just my 2 cents.
 
Das mit der lock-Datei ist auch eine Idee. Wenn die mal nicht gelöscht werden kann, gibts natürlich ein böses Problem. Evtl. so:

PHP:
// die Whitelist
$whitelist = array(
     'diswinamp','displs','diswmp','disreal','disflash',
     'itawinamp','itapls','itawmp','itareal','itaflash',
     'oldwinamp','oldpls','oldwmp','oldreal','oldflash'
);
// hier sind die echten Streamlinks eingetragen
$streamlinksPath = 'data/links.txt';
// der Pfad zu der Counter-Datei
$counterPath = 'data/counter.txt';
// die Datei, die für das lock zuständig ist
$filelockPath = 'data/counter.lock';
// Schreibversuche - man kann's wenigstens probieren
$writeRetries = 100;
// die StreamID, damit nicht immer $_GET geschrieben werden muss
$streamID = trim($_GET['id']);
// die dazu gehörenden URL - noch auf keinem Wert
$streamURL = false;

// wir prüfen auf Abbruchbedingen sofort zu Anfang
if ($streamID !== "" && in_array($streamID, $whitelist)) {
    if (($streams = file($streamlinksPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)) !== false) {
        // wir suchen die URL zur streamID
        foreach ($streams as $stream) {
            list($t_streamID, $t_streamURL) = explode('|', $stream);
            if ($t_streamID === $streamID) {
                $streamURL = $t_streamURL;
            }
        }
        // wenn ein Stream gefunden wurde
        if ($streamURL !== false) {
            // Versuche starten
            for($i=0,$written=false; ($i<$writeRetries && $written===false); $i++) {
                // wir probieren durch, ob die Lock-Datei existiert oder ob wir sie löschen können
                if ((!file_exists($filelockPath) || @unlink($filelockPath)) {
                    // öffne die Lock-Datei zum Schreiben bzw. erstelle diese. Sollte die Datei wider erwarten wieder existieren, wird abgebrochen
                    if ($filelockHandle = @fopen($filelockPath, 'xb')) !== false) {
                        // Schleife kann nach diesem Durchlauf beendet werden
                        $written = true;
                        // öffne den Counter zum lesen und schreiben
                        $counterHandle = fopen($counterPath, 'c+');
                        $counterLines = array();
                        // die Daten lesen
                        while (!feof($counterHandle)) {
                            $counterLines[] = fgets($counterHandle);
                        }
                        // Datei leeren
                        ftruncate($counterHandle,0);
                        // Datei-Pointer zurücksetzen
                        fseek($counterHandle,0);
                        // und die Zeilen wieder schreiben
                        foreach ($counterLines as $line) {
                            $expLine = explode("|", $line);
                            if ($expLine[0] === $streamID) {
                                $count = intval($expLine[1]) + 1;
                                $line = $streamID . '|' . $count . '|' . date('d.m.y.') . '|' . date('H:i') . "\n";
                           }
                           fputs($counterHandle, $line);
                        }
                        // brav alle Handles schliessen
                        fclose($counterHandle);
                        fclose($filelockHandle);
                        // die Lock-Datei löschen und so den (das?) lock freigeben
                        @unlink($filelockPath);
                    }
                }
            }
            // Header senden
            header('Location: ' . $streamURL);
            header('Cache-Control: must-revalidate, pre-check=0, no-store, no-cache, max-age=0, post-check=0');
            exit();
        }
    }
}
// Wenn alle Stricke reissen
header('Location: http://www.domain.eu');
exit();

Es ist klar, dass eine DB die viel bessere Lösung wäre, anstatt sich auf derart eifacher Ebene mit Dateien herumzuschlagen. Aber man darf's ja trotzdem probieren. Das Risiko kennt man ja...

edit: Hatte eine Klammer vergessen :(
Das Script kann recht langsam werden, funktioniert nach einem Test jetzt gerade aber einwandfrei.
 
Zuletzt bearbeitet:
Kay, das das mit dateien nicht perfect geht weis man ja. Aber wichtig wäre es auch alle Zugriffe zu zählen:
Meine idee:

Der Link geht nicht direkt auf den Stream sondern auf eine PHP Datei die einen Header sendet der den stream simuliert, dann wird der stream includet & am annfang wird halt der content geschrieben
 
@Master Bratack

Der Anbieter des Streams ist aber ein völlig anderer, als der, wo das Script aufgerufen wird. Man müsste also den Stream darüber durchschleifen, was den Traffic des Webspace in die Höhe treibt, und zwar für jeden angeforderten Stream doppelt, denn das Script muss für jeden User eine Verbindung zum Stream herstellen (Traffic-Eingang) und an den User weitergeben (Traffic-Ausgang). Des ist ineffektiv, und es bedingt ein unbegrenztes Ausführen des PHP-Scripts, was wiederum zum oben angesprochenen Problem führen kann, sogar mit weit extremeren Konsequenzen ("verstopfte Leitung").

Mal abgesehen davon könnte es sogar sein, dass der ein oder andere Musikplayer den Stream dann gar nicht verarbeiten kann ;)

Ergo: Gar keine gute Idee.

Das einzige, was man versuchen könnte, ist eine Header-Weiterleitung, wobei ich nicht weiß, ob ein Musikplayer des verarbeiten kann. Oder, was auch möglich ist, eine m3u-Musikliste per PHP generieren.
 
Das Problem sind glaube ich die Spider. Die sind das Übel denn sobald ich nämlich einen Player-Link in meiner Twitter Timeline poste habe ich auf einen Schlag 20-50 gleichzeitige Zugriffe auf die PHP-Datei,
das habe ich heute in der Log bemerkt.
Und auch das Script von @Garbanas hat versagt, die Textdatei wurde erneut zerschossen, einige Einträge fehlen auch komplett.

Also müsste man die Spider irgendwie fernhalten vom Script, wie kann man das und ist das überhaupt möglich? eventuell mit einer htaccess Datei die Spider erst garnicht in den Ordner lässt? ich denke dazu müsste man aber die ganzen Name der Spider kennen oder?
 
Du kannst versuchen die Bots via einer Robots.txt auszusperren, in der kannste ja fest definieren, welche Seiten nicht angesurft werden dürfen. In der Regel halten sich die Bots an diese Textdatei, ABER: Das ist keine Garantie.

Es gibt jedoch hunderte Bots. Die alle per Name auszusperren ist praktisch unmöglich. In dem Fall müssteste die User-Agents der Besucher speichern und so herausfinden, welche Bots deine Seite besuchen, darüber könntest du verhindern, dass dein Script dann reagiert.

Und das wiederum macht absolut nur dann Sinn, wenn du eine Datenbank nutzt, die du regelmäßig auf neue Bots prüfst, das geht praktisch nur manuell.


Btw, drücke mal ein paarmal hintereinander im Browser die Taste F5. Auch dadurch kannst du dir die Textdatei zerschießen - und du glaubst nicht, wie viele User aus Ungeduld andauernd F5 drücken wenn die Seite zu lahm lädt ;)
 
Hi

Mit der robot.txt geht es nicht, hab ich gerade mal versucht. Auch mit der htaccess geht es nicht, habe alle Spider die in meiner Log stehen eingefügt.

Das mit F5 verstehe ich jetzt nicht, F5 aktualisiert nur die Seite aber doch nicht das Script, das Script wird doch nur via Klick auf Link gestartet.
 
Ja ok aber das betrifft dann auch die Datenbank, auch dann kann man nonstop auf einen Link klicken der zur Datenbank verbindet.

Die schlimmsten Boots sind diese:
"askpeter_bot"
"Jakarta Commons-HttpClient"
"NaverBot"
"Twitturly"
"NjuiceBot"
"Voyager"
"PycURL"
"TweetmemeBot"
"Java"
"Yahoo! Slurp"
Diese greifen fast im Sekundentakt auf die Datei zu, die robot.txt ignorieren die und htaccess zeigt auch keine Wirkung.
 
Ja, natürlich verbindet des Script zur Datenbank, ABER du zerstörst damit nicht deine Daten^^

Was du machen könntest, speicher diese Namen in einem Array, z.B. $bot_blacklist. Dann prüfst du den User-Agent auf diese Namen (z.B. per stristr oder preg_match) und brichst das Script ab, wenn ein Treffer vorhanden ist.
 
Zurück zum eigentlichen Problem:

Ich würde in die "Datei.lock" die ProzessID des Scripts eintragen.

Dann kann man zwischen
Code:
$h = fopen($counterPath, 'r+');
und
Code:
ftruncate($h,0);
nochmal überprüfen, ob das existierende Lock tatsächlich von einem selber ist.

Falls ja, kann man die Datei ganz in Ruhe schreiben.
Wenn nicht, sollte man checken, ob der Prozess mit der hinterlegten ID noch läuft.
Wenn nicht, entfernt man das Lock.
Dann fängt man in beiden Fällen nochmal bei
Code:
if(file_exists($filelock))
an.


Ich würde im übrigen statt der Counter.txt immer in eine Counter.copy schreiben und die Counter.txt dann via Löschen der *.txt & Umbenennen der *.copy ersetzen.

Dadurch lässt sich verhindern, dass das PHP-Script während des Schreibens der Datei wegen max_execution_time oder anderer dinge gestoppt wird und somit eine defekte Datei hinterlegt wird.
 
Zurück
Oben