Auf das Thema antworten  [ 2 Beiträge ] 
Tutorial: Downloads mit Download-Skript mitzählen 
Autor Nachricht
Administrator
Benutzeravatar

Registriert: Sa 15. Dez 2012, 19:15
Beiträge: 137
Wohnort: Karlsruhe
Mit Zitat antworten
Hallo Leute!

Vielleicht habt ihr schon selbst festgestellt, dass ich die Downloads von Dateien auf meiner Homepage mithilfe eines Download-Skripts anbiete. Dabei nehme ich die Gelegenheit gleich wahr das Datum, die abgefragte Datei und die Seite, die auf das Download-Script verweist, zu speichern.

Dadurch entsteht eine hilfreiche Statistik. Sie kann darüber Auskunft geben, wann und wie oft eine Datei heruntergeladen wurde und welche Seiten auf den Downloadlink verweisen. So könnte ich auch herausfinden, wenn jemand - was man nicht macht und generell verboten ist - von seiner Internetseite direkt auf den Downloadlink verweist und nicht auf die Downloadseite. So suggeriert er nämlich dem User, dass der Inhalt von der ihm besuchten Internetseite stammte.

Also immer http://forum.magony.org/viewtopic.php?f=10&t=17 und nicht http://download.magony.org/?file=csharp ... ibrary.zip

Allerdings sollte das kein Problem mehr sein, seit dem man im Forum angemeldet sein muss um eine Datei downloaden zu können.

Ihr sieht, dass mein Downloadskript offensichtlich index.php heißt und sich in dem Ordner befindet, auf den der Besucher geleitet wird, wenn er auf download.magony.org kommt. Es wird der Pfad als GET-Variable übergeben. Um gleich irgendwelchen Spielerreien vorzubeugen: Dem Pfad wird ein "../" im Script hinzugefügt, sodass sich die Dateien in Ordnern befinden, die vom Internet nicht direkt aufrufbar sind. Allerdings können PHP-Scripte auf diese Ordner zugreifen.


Deshalb besteht mein Download-Skript größten Teils aus einer Methode, die ich auf http://de.php.net/manual/de/function.header.php#102175 gefunden habe. In der offiziellen Dokumentation können nämlich User noch weitere Beiträge hinzufügen die anderen Usern bezüglich der beschrieben Funktion helfen könnte. Und diese Methode hat mir geholfen!


Die zweite Funktion heißt dbVerbindung() und baut eine Verbindung mit meiner Datenbank auf. Da eine PHP-Datei nicht heruntergeladen werden kann, kann man hier durchaus seine Login-Daten direkt eingeben:
Code:
 
 function dbVerbindung() {
 mysql_connect("<server>", "<benutzer>", "<passwort>") or die ("Verbindung fehlgeschlagen");
 mysql_select_db("<db-name>") or die ("Datenbank konnte nicht ausgewählt werden");
 }
 


Ich muss noch eine dritte Funktion an dieser Stelle einfügen und damit eine Sicherheitslücke schließen.
Man hätte durch "falsche" Pfadangabe auf Dateien zugreifen können, die gar nicht freigegeben waren indem man z.B. den Pfad mit "../" oder "./" manipuliert hätte. Deshalb habe ich jetzt in jeden Ordner, in der sich Dateien befinden die auch heruntergeladen werden können sollen, eine 0-byte-Datei eingefügt "legaldownload.ini". Auf ihre Existenz prüfe ich hier. Das ist einfacher als eine Whitelist von Links oder Ähnlichem:
Code:
 
<?php // Zeile ist nur für das Einfärben des Codes
 function checkForBadLink($filename, $ip) {
        $path_parts = pathinfo($filename);
        if(!file_exists($path_parts['dirname'] . "/legaldownload.ini")){
                $log = ""; $logfile = "../badlink.log";
                if(file_exists($logfile)){
                        $log = fopen($logfile, "a");
                }
                else{
                        $log = fopen($logfile, "w");
                        fwrite($log, "<?php\n");
                }
                fwrite($log, "badlink[] = '$filename'; ip[] = '$ip'; time[] = '" . time() . "';\n");
                fclose($log);
                die("Bad link.");
        }
 }
 

Wenn der Ordner für den Download nicht freigegeben wurde, dann schreibt er mir ein log mit Link, Datum und der IP des Benutzers. Sollte sich hier ein Benutzer öfters eintragen, dann versucht er wohl eine Sicherheitslücke zu finden. Diese sollte mit dieser Maßnahme nun geschlossen sein. Die Funktion wird nun immer vor der Übernahme des Links aufgerufen.

Dann geht es nur noch um das Speichern der Infos:
Code:
 
<?php // Zeile ist nur für das Einfärben des Codes
 $pathpre = "../";
 
 if(isset($_GET['file'])) {
        $filename = $pathpre . mysql_real_escape_string($_GET['file']);
        checkForBadLink($filename, $_SERVER['REMOTE_ADDR']);
        if(file_exists($filename)) {
                dbVerbindung();
                mysql_query("INSERT INTO Downloaded (File, Referer) VALUES ('$filename', '".$_SERVER['HTTP_REFERER']."')");
        }
        else {
                $file = ""; $log = $pathpre . "_fails.log";
                if(!file_exists($log)) { $file = fopen($log, "a"); fwrite($file, "<?php\n"); } else { $file = fopen($log, "a"); }
                fwrite($file, "file[] = \"" . $filename . "\"; fail[] = \"Can not find the file\"; time[] =\"" . time() . "\";\n");
        }
        downloadFile($filename);
 }
 elseif(isset($_GET['info'])) {
        $filename = $pathpre . mysql_real_escape_string($_GET['info']);
        checkForBadLink($filename, $_SERVER['REMOTE_ADDR']);
        dbVerbindung();
        $abfrage = mysql_query("SELECT Date AS Datum FROM Downloaded WHERE File LIKE '" . $filename . "'");
        while($entry = mysql_fetch_object($abfrage)) {
                echo $entry->Datum . "\n";
        }
 }
 

Es passiert folgendes:
Ist die GET-Variable "file" gesetzt, dann wird geprüft, ob die Datei existiert.
Wenn ja, dann wird eine Verbindung zur Datenbank hergestellt und die Daten "file" und "HTTP_REFERER" werden eingetragen.
Wenn nein, dann wird eine Log-Datei erstellt oder die vorhandene fortgeführt. In sie wird der Fehler, das Datum und der Dateipfad gespeichert.

Die Log-Datei kann als PHP-Datei inkludiert werden, weil die Informationen dort so hineingeschrieben werden wie es in meinem Beitrag vorgeschlagen wird.
Ein Eintrag könnte so aussehen:
Code:
 
<?php
file[] = "Nichtgefunden.txt"; fail[] = "Can not find the file"; time[] = "31536000";
 
 

Nach dem Inkludieren der Datei könnte man auf drei Arrays zugreifen: file, fail und time. Die Einträge mit den jeweils gleichen Index gehören zusammen.

Sollte die Datei existieren oder nicht - auf jeden Fall wird die Methode zum Download der Datei gestartet. Sie prüft selbst noch einmal ob die Datei existiert und gibt entweder die Datei zurück oder "File not found.".


Sollte die GET-Variable "info" anstatt "file" verwendet worden sein, dann wird eine Datenbankabfrage gestartet, die dann die Daten zurückgibt, wann die Datei heruntergeladen wurde. An Hand der Zahl der ausgeworfenen Einträge kann man dann die Downloadzahl ermitteln. Wenn ich mehr Infos haben möchte, gehe ich einfach in phpMyAdmin() meiner Datenbank.

Und so ist meine Tabelle in meiner Datenbank aufgebaut:
Code:
Feld        | Typ       | Kollation         | NULL | Standard          | Extra          | Primär
_________________________________________________________________________________________________
Index       | int(11)   |                   | Nein |                   | auto_increment | TRUE
File        | tinytext  | latin1_german2_ci | Nein |                   |                |
Referer     | tinytext  | latin1_german2_ci | Ja   | NULL              |                |
Counter     | int(11)   |                   | Ja   | NULL              |                |
Date        | timestamp |                   | Nein | CURRENT_TIMESTAMP |                |

Tipp: Erstellt solche Tabellen am besten in einem Editor wie Notepad++. Ich muss mir noch überlegen, ob ich ein MOD - das ich bereits im Auge habe - installieren will, das das Ganze was einfacher macht. Aber MODs sind nicht unbedingt ungefährlich wenn man's falsch macht.

Wenn ich meine Tabelle eines Tages einmal aufräumen will, dann kann ich folgendes tun:

Beispiel: 01.11.2012 als Datum, Text.txt als Datei - wurde bis zum 01.11.2012 30 mal heruntergeladen.
Ich lösche die 30 Einträge und mache einen neuen mit dem Dateinamen, dem Datum und 30 als Counter. So sind 30 Einträge aus der Datenbank gelöscht, ohne die Downloadzahl in Vergessenheit geraten zu lassen.

Wenn ich diese einmal auswerten möchte, dann brauche ich alle Einträge der Datenbank mit dem jeweiligen Dateinamen und prüfe bei jedem Eintrag, ob Count gleich NULL ist. Wenn nicht, wird die Zahl dem Zähler hinzugefügt.


Schöne Grüße,
Magony

_________________
Bei Fragen, Lob, Kritik, Vorschläge, hilfreiche Hinweise oder Alternativvorschläge: Beitrag, neues Thema oder PN.
Für Dinge die diskutiert werden sollten, bitte neues Thema im jeweiligen Forum.
Wenn du nicht weißt wohin: Forum Unsortiert.


Di 18. Dez 2012, 23:12
Diesen Beitrag melden
Profil Website besuchen
Administrator
Benutzeravatar

Registriert: Sa 15. Dez 2012, 19:15
Beiträge: 137
Wohnort: Karlsruhe
Mit Zitat antworten
Hallo Leute!
Ich glaube ja nicht was ich da eben sehe: Ich genutze doch tatsächlich Eingaben vom Benutzer für eine SQL-Abfrage. Das sollte man natürlich niemal machen um SQL-Injection zu verhindern. Deshalb muss folgende Verbesserung vorgenommen werden:
Code:
 
<?php // Diese Zeile ist nur für das Einfärben des Codes
 
// Böser Code
     $filename = $pathpre . $_GET['file'];
// Sicherer Code
     $filename = $pathpre . mysql_real_escape_string($_GET['file']);
 


Habe heute den Code geändert.

Schöne Grüße,
Magony

_________________
Bei Fragen, Lob, Kritik, Vorschläge, hilfreiche Hinweise oder Alternativvorschläge: Beitrag, neues Thema oder PN.
Für Dinge die diskutiert werden sollten, bitte neues Thema im jeweiligen Forum.
Wenn du nicht weißt wohin: Forum Unsortiert.


Mo 15. Jul 2013, 17:24
Diesen Beitrag melden
Profil Website besuchen
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Auf das Thema antworten   [ 2 Beiträge ] 

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast


Du darfst neue Themen in diesem Forum erstellen.
Du darfst Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software
Deutsche Übersetzung durch phpBB.de

Impressum