Meowsalot: Insert fehlgeschlagen

Hallo alle,

ich habe heute bisschen mit einem jQuery Datei Upload beschäftigt. Leider hänge ich jetzt am PHP INSERT in meine MySQL Datenbank.


error_reporting(E_ALL);
ini_set('display_errors', 1);

if (isset($_FILES['attachments'])) {

	$msg		=  "";
	$targetFile = "upload/" . basename($_FILES['attachments']['name'][0]);

	// Eintrag in die Datenbank

	if ($stmt = $mysqli->prepare("INSERT INTO upload (referenzNr, datei) VALUES (?, ?)"))
       { 
        
        $referenzNr   = $_POST["code"];
        $dateit   	  = $_FILES['attachments']['name'][0]; 

        $stmt->bind_param("ss", $referenzNr, $datei);
        
        $stmt->execute();
        }
    else {
          echo $mysqli -> error;
    }

	// Eintrag Ende
		
			
	if (move_uploaded_file($_FILES['attachments']['tmp_name'][0], $targetFile)) {
		
		$msg = array(

					"status" => 1, 
					"msg" => "Datei wurde hochgeladen!", 
					"path" => $targetFile, 
					"Datei" => $_FILES['attachments']['name'][0]
				);
	}
	
	exit(json_encode($msg));
}

Es kommt keine Fehlermeldung. In den Entwicklertools erhalte ich folgendes

<b>Notice</b>: Undefined index: code in <b>/upload.php</b> on line <b>24</b><br />

{"status":1,"msg":"Datei wurde hochgeladen!","path":"upload/2.png","Datei":"2.png"}

Die Datei befindet sich auf dem Server. Fehlermeldung erhalte ich keine.

<div id="dropZone">
	<h1> Drag & Drop Files ... </h1>
	<input type="file" id="fileupload" name="attachments[]" multiple ">
	<input type="hidden" id="code" name="code" value="2587">
</div>

Kann ich bei einem jQuery Upload gar kein hidden-Feld mitgeben? Sollte es noch wichtig sein, hier mein jQuery Script

$(function () {

		var files = $("#files");

		$("#fileupload").fileupload ({
			
			url: 'upload.php',
			dropZone: '#dropZone',
			dataType:'json',
			autoUpload: false

		}).on('fileuploadadd', function (e, data) {

			var fileTypeAllowed = /.\.(gif|jpg|png|jpeg)$/i;
			
			var fileName = data.originalFiles[0]['name'];
			var fileSize = data.originalFiles[0]['size'];
			
			if (!fileTypeAllowed.test(fileName)) {
				$("#error").html('Nur Bilder erlaubt!');
			} else {
				$("#error").html("");
				data.submit();
			}

		}).on('fileuploaddone', function (e, data) {

			var status = data.jqXHR.responseJSON.status;
			var msg = data.jqXHR.responseJSON.msg;

			if (status == 1) {
				console.log(data);
				var datei = data.jqXHR.responseJSON.Datei;
				$("#files").fadeIn().append('<p>'+datei+'</p>');
				//var path = data.jqXHR.responseJSON.path;
				//$("#files").fadeIn().append('<p><img class="files" src="'+path+'" alt=""></p>');
			} else {
				$("#error").html(msg);
			}

		}).on('fileuploadprogressall', function (e, data) {

			var progress = parseInt(data.loaded / data.total * 100, 10);
			$('#progress').html("Vollständig:" + progress + "%");

		});
	});

Bis bald!
Meowsalot (Bernd)

  1. Tach!

    Kann ich bei einem jQuery Upload gar kein hidden-Feld mitgeben?

    Du wirst vermutlich auch noch andere Daten mitgeben können, aber die kommen nicht von allein in den Request, nur weil du in deinem Dokument ein paar input-Elemente hast. Du musst die selbst zusammensuchen/zusammenstellen und der Upload-Komponente mit auf den Weg geben. Wie und ob das geht, musst du in deren Dokumentation nachlesen.

    dedlfix.

  2. Hi,

    	if ($stmt = $mysqli->prepare("INSERT INTO upload (referenzNr, datei) VALUES (?, ?)"))
           { 
            $stmt->bind_param("ss", $referenzNr, $datei);
            $stmt->execute();
            }
        else {
              echo $mysqli -> error;
        }
    

    Es kommt keine Fehlermeldung.

    Du wertest die Rückgabe (und ggf. die Fehlermeldung) von bind und execute immer noch nicht aus. Wurde doch schon in einem der anderen Threads gesagt, daß Du das tun solltest.

    cu,
    Andreas a/k/a MudGuard

    1. Hallo MudGuard,

      Du wertest die Rückgabe (und ggf. die Fehlermeldung) von bind und execute immer noch nicht aus. Wurde doch schon in einem der anderen Threads gesagt, daß Du das tun solltest.

      ich habe bis jetzt noch in keinem Tutorial nachlesen können wie ich die Rückgabe auswerten kann. Es kommt immer nur, dass ich mir

      echo $mysqli -> error;
      

      ausgeben lassen soll.

      Bis bald!
      Meowsalot (Bernd)

      1. Hallo @Meowsalot,

        ich habe bis jetzt noch in keinem Tutorial nachlesen können wie ich die Rückgabe auswerten kann. Es kommt immer nur, dass ich mir

        das ist zwar kein Tutorial, aber dafür die offizielle Dokumentation der mysqli_stmt-Klasse. Da steht, dass diese Methoden Rückgabewerte haben – und als Bonus ist die Dokumentation der jeweiligen Methode gleich mit verlinkt.

        Viele Grüße
        Robert

      2. Tach!

        Du wertest die Rückgabe (und ggf. die Fehlermeldung) von bind und execute immer noch nicht aus. Wurde doch schon in einem der anderen Threads gesagt, daß Du das tun solltest.

        ich habe bis jetzt noch in keinem Tutorial nachlesen können wie ich die Rückgabe auswerten kann.

        Du solltest zu jeder Funktion ins PHP-Handbuch schauen und ihre Arbeitsweise nachlesen. Insbesondere auch ihr Verhalten im Fehlerfall, das ebenfalls im Abschnitt zum Rückgabewert beschrieben ist. Der Rest ist im Prinzip einfaches Programmieren mit if-then-else. Du wertest ja bereits den Rückgabewert vom prepare() aus, die beiden anderen erwähnten Stellen arbeiten bezüglich möglicher Fehler nach demselben Prinzip.

        Es kommt immer nur, dass ich mir echo $mysqli -> error; ausgeben lassen soll.

        Das ist nur das Ermitteln der Ursache, was aber auch beim Execute sinnvoll ist Beim Binden wird es wohl eher nicht zu Fehlern kommen. Fehlerbehandlung ist aber eigentlich noch weit mehr als nur das Abfragen und Anzeigen des Textes. Eigentlich soll der Text gar nicht in die Ausgabe, sondern irgendwohin, wo es der Administrator auch im Nachhinein noch nachlesen kann, sprich: Logfile. Bei einem Fehler ist es aber auch sinnvoll, den Anwender zu informieren, dass das Programm nicht weiterarbeiten kann. Aber Details braucht er keine zu wissen, solange er nicht am Problem selbst schuld ist (wie etwas bei falschen Eingabewerten). Jedenfalls solltest du dir aber Gedanken machen, was denn im Fehlerfall am besten zu tun ist. Mindestens irgenein geordnetes Abschließen des Vorgangs und kein abruptes Sterben. Der Rest hängt vom Anwendungsfall ab, und ob man dem Anwender irgendeine Alternative bieten kann.

        dedlfix.

  3. Zur Fehlerbehandlung mit AJAX:

    Du hast hier einen Client und einen Server die asynchron kommunizieren. D.h., daß ein etwaiger serverseitiger Fehler auch den Weg zurück zum Benutzer finden sollte. Wenn ein Ajax Request aufm Server in die Hose geht, muss man also auch dafür sorgen daß es im DOM ankommt.

    Damit der Client das von einer regulären Response unterscheiden kann, könnte man den Response Status heranziehen. D.h., daß Deine serverseitig Fehlerbehandlung schonmal einer solchen Anforderung gerecht werden muss. Tut sie das? Ich kann leider nichts dergleichen erkennen.

    MfG

  4. Hallo @Meowsalot,

    könnte das

    $referenzNr   = $_POST["code"];
    

    Zeile 24 sein?

    Es kommt keine Fehlermeldung. In den Entwicklertools erhalte ich folgendes

    <b>Notice</b>: Undefined index: code in <b>/upload.php</b> on line <b>24</b><br /> {"status":1,"msg":"Datei wurde hochgeladen!","path":"upload/2.png","Datei":"2.png"}

    Korrekt, das ist eine Notiz und keine Fehlermeldung – außer, du machst daraus einen Fehler.

    <div id="dropZone">
    	<h1> Drag & Drop Files ... </h1>
    	<input type="file" id="fileupload" name="attachments[]" multiple ">
    	<input type="hidden" id="code" name="code" value="2587">
    </div>
    

    Die Inputs gehören nicht zu einem form.

    Kann ich bei einem jQuery Upload gar kein hidden-Feld mitgeben?

    Versteckte Fehler gehören wie normale Eingabecontrols afaik zu einem Formular.

    Mal noch eine andere Frage: Was für Datenmengen werden denn da übertragen, dass eine Fortschrittsanzeige nötig erscheint?

    Viele Grüße
    Robert

    1. Hallo Robert,

      $referenzNr   = $_POST["code"];
      

      Zeile 24 sein?

      genau. Ich benötige für einen neuen Eintrag in die Datenbank eine Referenz um die Dateien meiner To-Do zuordnen zu können. Wenn ich ein Eintrag bearbeite dann habe ich diese. Bei einem neuen Eintrag leider noch nicht. Deshalb wollte ich dieses über das versteckte Feld machen.

      <div id="dropZone">
      	<h1> Drag & Drop Files ... </h1>
      	<input type="file" id="fileupload" name="attachments[]" multiple ">
      	<input type="hidden" id="code" name="code" value="2587">
      </div>
      

      Die Inputs gehören nicht zu einem form.

      Kann ich bei einem jQuery Upload gar kein hidden-Feld mitgeben? Versteckte Fehler gehören wie normale Eingabecontrols afaik zu einem Formular.

      Hmm Ok. Dann bleibt mir nur den Weg:

      $referenzNr = "2589";
      

      Und denn Wert beim Aufruf der Seite neu zu setzten. Damit habe ich wieder eine eindeutige Zuordnung.

      Mal noch eine andere Frage: Was für Datenmengen werden denn da übertragen, dass eine Fortschrittsanzeige nötig erscheint?

      Wenn ich Bilder hochlade, können dieses gerne mal 10 - 100 MB sein, da ist ein Fortschritt nicht schlecht.

      Bis bald! Meowsalot (Bernd)

      1. Hallo @Meowsalot,

        Ich benötige für einen neuen Eintrag in die Datenbank eine Referenz um die Dateien meiner To-Do zuordnen zu können. Wenn ich ein Eintrag bearbeite dann habe ich diese. Bei einem neuen Eintrag leider noch nicht. Deshalb wollte ich dieses über das versteckte Feld machen.

        Joa, also warum kein form verwenden? In deinem JavaScript-Code wird ja auch irgendwo ein .submit aufgerufen, das könnte ja auch ein form sein. Alternativ kannst du auch die ID per GET übertragen.

        Die Inputs gehören nicht zu einem form.

        Kann ich bei einem jQuery Upload gar kein hidden-Feld mitgeben? Versteckte Fehler gehören wie normale Eingabecontrols afaik zu einem Formular.

        Hmm Ok. Dann bleibt mir nur den Weg:

        Und was spricht gegen den HTML-Weg mit form?

        Viele Grüße
        Robert

        1. Hallo Robert,

          Joa, also warum kein form verwenden? In deinem JavaScript-Code wird ja auch irgendwo ein .submit aufgerufen, das könnte ja auch ein form sein. Alternativ kannst du auch die ID per GET übertragen.

          GET funktioniert leider nicht, auch hier ist kein INSERT möglich. Warum nicht über ein <form>? Weil ich später dann zwei Formulare auf meiner Seite habe. Einmal eines für meine To-Do Liste und ein zweites für den Upload. Da komme ich doch ins Teufelsküche?

          Und ja, ich habe den Submit

          else {
          				$("#error").html("");
          				data.context = $('#hinweis').html("Uploading ......");
          				data.submit();
          			}
          

          Ok, so kann ich auch ein verstecktes Feld mitgeben

          <div id="dropZone">
          	<h1> Drag & Drop Files ... </h1>
          	<form method="post" id="fileupload1"> 
          	<input type="file" id="fileupload" name="attachments[]" multiple ">
          	<input type="hidden" id="code" name="code" value="2587">
          	</form>
          </div>
          

          Bis bald!
          Meowsalot (Bernd)

          1. Hallo @Meowsalot,

            GET funktioniert leider nicht,

            definiere „funktioniert nicht“.

            auch hier ist kein INSERT möglich.

            Interessant wäre zu wissen, warum?

            Warum nicht über ein <form>? Weil ich später dann zwei Formulare auf meiner Seite habe. Einmal eines für meine To-Do Liste und ein zweites für den Upload.

            Und das sind semantisch zwei unterschiedliche Formulare mit unterschiedlichen actions?

            Da komme ich doch ins Teufelsküche?

            Wieso?

            Und ja, ich habe den Submit

            data.submit();
            

            Was ist denn data für ein Objekt?

            Viele Grüße
            Robert

            1. Hallo Robert,

              GET funktioniert leider nicht, definiere „funktioniert nicht“.

              Mehr kann ich dir leider nicht sagen. Es kommt kein Eintrag in der Datenbank an.

              auch hier ist kein INSERT möglich. Interessant wäre zu wissen, warum?

              Würde mich auch interessieren.

              Bis bald!
              Meowsalot (Bernd)

              1. Hallo @Meowsalot,

                Mehr kann ich dir leider nicht sagen. Es kommt kein Eintrag in der Datenbank an.

                Dann wird es Zeit für Debugging. Ein PHP-Programm ist keine Blackbox (außer man ignoriert z.B. Rückgabewerte oder Warnungen).

                auch hier ist kein INSERT möglich. Interessant wäre zu wissen, warum?

                Würde mich auch interessieren.

                S.o.

                Viele Grüße
                Robert

      2. Hallo Meowsalot,

        YELLOW ALERT

        Wenn ich ein Eintrag bearbeite dann habe ich diese. Bei einem neuen Eintrag leider noch nicht. Deshalb wollte ich dieses über das versteckte Feld machen.

        Erzähl doch mal schnell was über dein Concurrency-Konzept. Konkret: wie stellst Du sicher, dass nicht zwei parallel arbeitende User die gleiche "neue ID" erhalten?

        Rolf

        --
        sumpsi - posui - clusi
        1. Hallo Rolf,

          Erzähl doch mal schnell was über dein Concurrency-Konzept. Konkret: wie stellst Du sicher, dass nicht zwei parallel arbeitende User die gleiche "neue ID" erhalten?

          Wenn ein Eintrag bearbeitet wird habe ich eine eindeutige ID. Wenn ich einen neuen Eintrag erstelle mache ich das mit $id = time();

          Da kann ich so gut wie sicher sein, dass ich keine Doppelten Einträge erhalte.

          Bis bald! Meowsalot (Bernd)

          1. Hallo Meowsalot,

            nein, da kannst Du nicht sicher sein. "So gut wie sicher" ist ein Unfall, der darauf wartet, zu passieren.

            Neuen Einträgen gibt man die ID normalerweise erst beim Insert. Da hat man dann eine in sich abgeschlossene Operation, die die Eindeutigkeit sicherstellen kann.

            Rolf

            --
            sumpsi - posui - clusi
            1. Hallo Rolf,

              und wie würdest du dann in diesem Fall vorgehen:

              1. User füllt eine To-Do aus, das Formular wurde noch nicht abgeschickt
              2. User lädt im Hintergrund über einen Ajax Upload Dateien/Bilder zu dieser To-Do hoch.

              Beide sollen später wieder zueinander finden. Also benötige ich eine passende ID für beide Bereiche. Wenn ich eine ID/einen Code erst beim Insert erzeuge finde ich die Bilder nie wieder.

              Bis bald! Meowsalot (Bernd)

              1. Hallo Meowsalot,

                guter Hinweis.

                Aber die Uploads dürfen ja nicht im luftleeren Raum landen, sondern müssen einen Fremdschlüssel haben, zu dem sie gehören. Dieses Problem musst Du auch bei einer vorgenerierten ID lösen. Willst Du Medien zu einer Upload-ID speichern, die gar nicht in der Todo-Tabelle steht? D.h. bevor Du einen Upload machen kannst, muss das Todo in die Datenbank.

                Das kannst Du dem User entweder explizit machen, indem Du einen Medienupload erst erlaubst nachdem ein "Speichern" Button gedrückt wurde, oder Du machst dieses Speichern als eigenen Ajax unter der Haube, wenn der User auf "Upload" drückt. Der erste Ajax liefert dann die ID und die kannst Du dem Upload-Ajax mitgeben. Ich stelle mir das so vor: User selektiert Medium und klickt Upload, Webseite zeigt "Speichere neues Todo", ruft Speichern AJAX, bei Eintreffen der Antwort wird "Speichere Datei" angezeigt und das zweite Ajax gestartet, kommt das zurück, kann man weitermachen.

                Rolf

                --
                sumpsi - posui - clusi
              2. hallo

                Hallo Rolf,

                und wie würdest du dann in diesem Fall vorgehen:

                1. User füllt eine To-Do aus, das Formular wurde noch nicht abgeschickt
                2. User lädt im Hintergrund über einen Ajax Upload Dateien/Bilder zu dieser To-Do hoch.

                Beide sollen später wieder zueinander finden. Also benötige ich eine passende ID für beide Bereiche. Wenn ich eine ID/einen Code erst beim Insert erzeuge finde ich die Bilder nie wieder.

                Ich gehe davon aus, dass du ein SessionID_Token als Cookie hast. Ich gehe davon aus, dass du ein CSRF_Token hast, das vom SessionID_Token abgeleitet ist, und explizit NICHT im Cookie gesendet wird sondern als Teil von Form-Data. Genau dieses CSRF_Token lässt sich verwenden, um User-Uploads sauber zu trennen. Denn dieses ist auf jeden Fall überprüfbar.

  5. Hallo Meowsalot,

    	<input type="file" id="fileupload" name="attachments[]" multiple ">
    

    Der Quelltexthochlichter zeigt noch einen Fehler.

    Bis demnächst
    Matthias

    --
    Rosen sind rot.