facebraker
Goto Top

Kann in DB gespeicherte Daten nicht mehr auslesen

Hallo,

ich habe vor Jahren mit einen kleinen Projekt angefangen, soll ein Extranet werden.
Mitarbeiter können Dateien hochladen und Kunden können die Dateien bei sich herunterladen.

Jedenfalls habe ich es wieder aufgegriffen und versuche es wieder auf die Beine zu stellen.

Das hochladen der Dateien funktioniert perfekt, das herunterladen nicht.

Ich habe einen Button, der eine PHP Datei aufruft, mit einer Action "download" und der ID der Datei in der
Mysql Datenbank:

if($_GET['todo']==download) {  
    $id_files=$_GET['id'];  
    $connectionid = mysql_connect ("localhost", "user", "password");   
    if (!mysql_select_db ("intranet", $connectionid)) {   
        die ("Keine Verbindung zur Datenbank");   
    } 
    $sql = "SELECT content, type, name, size FROM upload WHERE id=$id_files";  
         	
    $result = @mysql_query($sql, $connectionid);
    if ( !$result ) die('MySQL-Fehler:' . mysql_error()); 	  
    $data = @mysql_result($result, 0, "content");  
    $name = @mysql_result($result, 0, "name");  
    $size = @mysql_result($result, 0, "size");  
    $type = @mysql_result($result, 0, "type");  
	
    header("Content-type: $type");  
    header("Content-length: $size");  
    header("Content-Disposition: attachment; filename=$name");  
    header("Content-Description: PHP Generated Data");  
    echo $data;
    mysql_close($connectionid);
}

Eigentlich sollte ich ja dann einen Datei-Download bekommen, läuft aber nicht face-sad

Was mache ich falsch?

Danke Gruß Alex

Content-Key: 195880

Url: https://administrator.de/contentid/195880

Printed on: April 19, 2024 at 15:04 o'clock

Member: firefly
firefly Dec 14, 2012 at 15:53:40 (UTC)
Goto Top
Hi @facebraker,

lass Dir als erstes doch mal die $sql Variable ausgeben und überprüfe damit dann die Datenbank. Dann würde ich auch die "@" Zeichen vor den "mysql_" Befehlen löschen, da das @ mögliche Fehlermeldungen unterdrückt. So von der Syntax sollte es korrekt sein.

Gruß
@firefly
Member: bytecounter
bytecounter Dec 14, 2012 at 18:19:05 (UTC)
Goto Top
Moin,

also ich stell mir erst einmal die Frage, was kommt denn überhaupt? Wenn kein Download kommt, muss ja ein Warning, eine Exception oder sonst was kommen.

Könnte mir auch vorstellen, dass Dein Script noch auf einer alten PHP-Version basiert, der Server aber zwischenzeitlich auf einer neueren Version läuft.

vg
Member: facebraker
facebraker Dec 14, 2012 at 18:23:28 (UTC)
Goto Top
Hallo Firefly, ich habe das Skript mal schön gemacht.

<?php
error_reporting( -1 );
ini_set('display_errors', TRUE);  

session_start (); 
#include ("checkuser.php");  
#echo $_GET ['id']; 
#echo $_SESSION["user_id"]; 
if(isset($_GET['id']) && isset ($_SESSION["user_id"]))    
{
  $connectionid = mysql_connect ("localhost", "user", "password");  
  #echo $_GET['todo']; 
  if($_GET['todo']==download)  
  {
      $id_files=$_GET['id'];  
      if (!mysql_select_db ("intranet", $connectionid)) die ("Keine Verbindung zur Datenbank");   
        $sql = "SELECT content, type, name, size FROM upload WHERE id=$id_files";  
        $result = mysql_query($sql, $connectionid);
      echo $sql;
      if ( !$result ) die('MySQL-Fehler:' . mysql_error());     
      $data = mysql_result($result, 0, "content");  
      $name = mysql_result($result, 0, "name");  
      $size = mysql_result($result, 0, "size");  
      $type = mysql_result($result, 0, "type");  
        
      #header("Content-type: $type"); 
      #header("Content-length: $size"); 
      #header("Content-Disposition: attachment; filename=$name"); 
      #header("Content-Description: PHP Generated Data"); 
      echo $data;
      
    }
    elseif ($_GET['todo']==delete)  
    {
        $id_files=$_GET['id'];  
        if (!mysql_select_db ("intranet", $connectionid)) die ("Keine Verbindung zur Datenbank");   
      $sql = "DELETE FROM upload WHERE id=$id_files";  
        $result = mysql_query($sql, $connectionid);
        if ( !$result ) die('MySQL-Fehler:' . mysql_error());     
     }
    mysql_close($connectionid);
    Header('Location: projekt_portal.php');  
  }
?>

Komischerweise wird kein "echo" ausgegeben, auch nicht als Debug, könnte das der Fehler sein?

Gruß Alex
Member: bytecounter
bytecounter Dec 14, 2012 at 18:43:52 (UTC)
Goto Top
Versteh ich jetzt nicht...ein echo als debug? Also entweder da ist ein echo, dann wird das auch ausgegeben - oder da ist eben keins.

Wenn er schon in Zeile 19 nix ausgibt, dann passt da was nicht. Ist das das komplette Script? Rufst Du das direkt auf? Oder gibt's da vorher noch was?
Zeile 19 würde ich vor Zeile 18 schreiben. Danach mal ein exit; Dann muss er ja zumindest die Query ausgeben.

vg
Member: nxclass
nxclass Dec 14, 2012 updated at 22:08:43 (UTC)
Goto Top
beachte dass gewisse Wörter zum SQL Syntax von MySQL gehören.
SELECT `content`, `type`, `name`, `size`
FROM `upload`
WHERE `id`= $id_files
... um Problemen mit dem Escape der Parameter auszuschließen würde ich Dir empfehlen bind zu nutzen oder gleich PDO.

EDIT:
  • benutze lieber var_dump() für debug ausgaben
  • if($_GET['todo']==download) ... was ist download ? - eine Konstante ? ... ich glaube nicht. benutze mal error_reporting(E_ALL);
Member: facebraker
facebraker Dec 16, 2012 at 11:25:32 (UTC)
Goto Top
Hallo!

Ich habe eure Anmerkungen z.T. umgesetzt.

if($_GET['todo']==download) ist wirklich dämlich face-sad natürlich muss es if($_GET['todo']=='download') heißen, aber ich wundere mich warum es trotzdem im "delete" Zweig geht?

Ja, das Skript ist nicht alles.

Ich habe eine Seite, wo in einer Tabelle die Dateien in der DB angezeigt sind, in jeder Zeile sind 2 Button "Download" und "Delete" , wenn der Nutzer "Delete" drückt, wird das Skript aufgerufen und die "id" des Datensatzes in der DB übergeben und die "userid". Beim "Download" das gleiche ... aber der Download klappt sind, es passiert einfach nichts, wenn ich "Download" klicke sagt der Browser "warten auf localhost (WAMP)" und weiter nichts.

Meine Vermutung, das "echo $data" wird zwar ausgeführt aber irgendwie geblockt, Browser oder PHP???? Keine Ahnung.

Das mit mysqli und PDO muss ich auch umsetzen, aber mit Laptop und keiner richtigen Tastatur und Maus ist das nervig, wenn dann schaffe ich es Montag am Schreibtisch face-wink

Aber abgesehen von der Anfälligkeit für SQL Injenctions muss es ja funktionieren.

Gibt es im PHP eine globale Variable die Fehlermeldungen auf ein mindest Log-Level setzt, dass ich kein Feedback bekomme?

Gruß Alex
Member: facebraker
facebraker Dec 16, 2012 at 12:12:15 (UTC)
Goto Top
Hi habe jetzt auf mysqli umgestellt, erstmal nur den "download" Zweig, aber keine Änderung.

<?php
#error_reporting( -1 );
error_reporting(E_ALL);
ini_set('display_errors', TRUE);  

session_start (); 
#include ("checkuser.php");  
#echo $_GET ['id']; 
#echo $_SESSION["user_id"]; 
if(isset($_GET['id']) && isset ($_SESSION["user_id"]))    
{
	$connectionid = mysqli_connect ("localhost", "intranet", "intranet");  
	#echo $_GET['todo']; 
	if($_GET['todo']=='download')  
	{
			$id_files=$_GET['id'];  
			if (mysqli_connect_errno($connectionid)) {
    			echo "Failed to connect to MySQL: " . mysqli_connect_error();  
				}
	  		$sql = "SELECT 'content', 'type', 'name', 'size' FROM upload WHERE 'id'=$id_files";  
	  		var_dump( $sql);
	  		if ($result = mysqli_query($connectionid, $sql)) {

		    /* fetch associative array */
    		while ($row = mysqli_fetch_assoc($result)) {
        			$name = $row["name"];  
        			$size =  $row["size"];  
        			$type =  $row["type"];  
        			$data=  $row["content"];  
        	}

    		/* free result set */
    		mysqli_free_result($result);
			}

			header("Content-type: $type");  
			header("Content-length: $size");  
			header("Content-Disposition: attachment; filename=$name");  
			header("Content-Description: PHP Generated Data");  
			echo $data;
	}
	  mysqli_close($connectionid);
	  Header('Location: projekt_portal.php');  
  }
?>



*Grübel* geht nicht, wieder keine Reaktion, baue ich Fehler ins Skript, dann kriege ich Fehlermeldungen, aber so nicht.

Gruß Alex
Member: nxclass
nxclass Dec 16, 2012 updated at 19:52:35 (UTC)
Goto Top
Beachte die Backticks ` - nicht die Hochkommas ' verwenden im SQL, dann gibt dir die SELECT Anweisung die Tabellen Feldnamen als Konstanten zurück.

EDIT:
  • Wenn deine DB Verbindung fehlschlägt - wird nach dem IF() trotzdem weitergearbeitet. - daher ein exit() oder throw new Exception() einfügen
  • In WHILE: var_dump( $row )
  • Wenn deine SQL Anweisung einen Fehler produziert - also $result === false ist - was dann ? - eine Ausgabe des SQL Errors würde bestimmt gut in einen ELSE Zweig passen
Member: bytecounter
bytecounter Dec 16, 2012 updated at 20:50:24 (UTC)
Goto Top
Hallo,

man kann die Ausgabe mit PHP zwar nicht blocken, aber z. B. mit ob_start() erst einmal zurückhalten. Sobald das Script aber beendet wird, wird alles ausgegeben, was im Puffer steht. Allerdings kann dieser zwischendrin auch z. B. mit ob_clean() ohne Ausgabe geleert werden. Da sehe ich in Deinem Script aber nicht; dazu könnte natürlich in dem aufrufenden Script was stehen.

Um den Fehler zu suchen, könntest Du ein einfaches Script schreiben, welches Du direkt im Browser aufrufst. Dort sind keine IFs und keine $_GETs..sondern einfach nur z. B.
$id = 5;
$dbh = mysqli_connect ("localhost", "intranet", "intranet");   
$query = "SELECT * FROM upload WHERE id=$id";  
echo "Query: $query <br>";  
$result = mysqli_query($dbh, $query);
var_dump($result);

Dann mal schauen, was er dazu sagt.

vg
Member: bytecounter
bytecounter Dec 17, 2012 at 08:56:56 (UTC)
Goto Top
Sowas ähnliches hatte er vorher schon, allerdings mit die(); was ja grundsätzlich auf das gleiche rauskommt. Ist zwar auch nicht sauber, aber das Script ist ja auch schon älter ;)

Mein gestern gepostete Script sollte etwas Licht ins Dunkel bringen. Die Sache mit den Backticks hab ich auch schon vermutet. Daher hab ich das in meinem Bsp "anders" gelöst. Mal schauen, was facebraker postet.

Euch allen eine angenehme und stressfreie Vorweihnachtswoche!

vg
Bytecounter
Member: facebraker
facebraker Dec 17, 2012 at 11:21:41 (UTC)
Goto Top
Hallo Bytecounter & nxclass,

ich hatte gestern Abend richtig die Schnautze voll, und frei nach der Debugging-Regel "Wenn was nicht funktioniert, gehe davon aus, dass das komplette Skript fehlerhaft ist" habe ich noch einmal von Null angefangen.

Das das Skript nicht so spektakulär war, habe ich es von Anfang an versucht sauber zu programmieren.

ABER, ich denke mal nxclass hat recht mit den Backticks, denn in meinen neuen Skript verwende ich ein Select * from upload WHERE... Das könnte der Fehler sein. Denn viel anders mache ich es in den neuen Skript auch nicht.
Bis auf mysqli_* und mysqli_real_escape_string ..


Jedenfalls mein neues funktioniert, vielen Dank für Eure Tipps!

<?php 
session_start (); 
// DB
$link = mysqli_connect("localhost", "intranet", "intranet","intranet");   

if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());  
    exit();
}

if (isset($_GET['id']) &&  isset ($_SESSION["user_id"])) {   
	if($_GET['todo']=='download'){  
		// SQL String
		$sql = sprintf("SELECT * FROM upload WHERE id = '%s' LIMIT 1", mysqli_real_escape_string($link,$_GET['id']));  
		if ($result = mysqli_query($link, $sql)) {

				/* fetch associative array */
				while ($row = mysqli_fetch_assoc($result)) {
					printf ("%s (%s)\n", $row["Name"], $row["CountryCode"]);  
					// Den Browser zum Download zwingen 
					header("Content-type: " . $row["type"]);   
					header("Content-disposition: attachment; filename=".$row["name"].";");   
					header("Content-length: " . $row["size"]);   

					// Daten dekodieren und an den Browser senden 
					echo $row["content"];   

				}

				/* free result set */
				mysqli_free_result($result);
			}
		
		/* close connection */
		mysqli_close($link);
		exit; 
		}
	elseif ($_GET['todo']=='delete') {  
		$sql = sprintf("DELETE FROM upload WHERE id='%s'",mysqli_real_escape_string($link,$_GET['id']));  
	  	$result = mysqli_query($link,$sql);
	  	if ( !$result ) die('MySQL-Fehler:' . mysqli_error($link)); 	  
		}
		Header('Location: http://localhost/extranet/projekt_portal.php');  
} 
?>


Gruß Alex
Member: bytecounter
bytecounter Dec 17, 2012 at 11:57:21 (UTC)
Goto Top
Freut mich, dann den Thread bitte noch als gelöst markieren.

Allerdings noch ein Tip: Um das Script ein wenig abzusichern, solltest Du keine Variablen direkt (also ungefiltert) an den SQL übergeben.
Bei einer ID (welche vermutlich ein Integer ist), ist das recht einfach:

$id = (int) $_GET['id'];

Ist es ein String, müsstest Du ihn auf erlaubte Zeichen prüfen. Da Du das aber nur intern einsetzt- und ich vermute, dass der Server von außen gar nicht erreichbar ist, ist das nicht ganz so dramatisch.

Weiterhin viel Erfolg!

vg
Bytecounter
Member: facebraker
facebraker Dec 17, 2012 at 14:05:10 (UTC)
Goto Top
Hallo Bytecounter,

Danke für den Tipp, da habe ich mich schon belesen und es wurde empfohlen dies zu nuten:

mysql_real_escape_string — Maskiert spezielle Zeichen innerhalb eines Strings für die Verwendung in einer SQL-Anweisung

http://php.net/manual/de/function.mysql-real-escape-string.php

Natürlich ist deine Lösung, so einfach wie genial face-smile

Aber mysql_real_escape_string sollte auch reichen, oder?

Danke, ich bin schon am nächsten Problem, würde mich freuen wenn du die Augen im Forum offen hälst und mir eventuell da helfen kannst.

Vielen Dank!

Gruß Alex
Member: bytecounter
bytecounter Dec 17, 2012 at 23:26:33 (UTC)
Goto Top
Hallo Alex,

das kannst Du natürlich auch nehmen.

vg
Bytecounter