WernerK: Fatal error: Allowed memory size of 52428800 bytes exhausted

Hallo
memory_limit, max_filesize und post_max_size steht alles auf 50MB

Ich kann eine 9 MB Datei problemlos hochladen.
Doch an einer anderen Stelle im PHP Script mit

$inhalt = file($upload . "/" . $myfile);

kommt obiger Fehler.

Ich verstehe nicht ganz warum. Die Datei ist doch nur 9 MB, AUch andere bzw. sogar noch größere Dateien kann ich hochladen und dann verarbeiten ohne Fehler.

Kann das auch am Dateiinhalt liegen?

Die Größe wird schon richtig erkannt
Test mit;
$testfile = filesize($upload . "/" . $myfile);
echo "die file size ist $testfile <br>";

Gruss
Werner

  1. Hallo!

    Doch an einer anderen Stelle im PHP Script mit

    $inhalt = file($upload . "/" . $myfile);

    kommt obiger Fehler.

    Bist du dir sicher, dass du nicht irgendwo eine Endlosschleife eingebaut hast?

    Kann das auch am Dateiinhalt liegen?


    Bei der Verarbeitung von Grafiken
    kenne ich das Problem. Wenn es nur um den upload an und für sich geht, hatte ich das Problem noch nicht. Da du deinen Code nicht gepostet hast, tippe ich erstmal auf eine Endlosschleife.

    Grüße, Matze

    1. Hallo Matze~~~php

      danke dir,
      nein da ist keine Endlosschleife drin. Wie gesagt das passiert ja nur bei diesem File. Andere files mit 9 MB ode soagr 12 MB machen keine Probleme.

      hier noch der Code..

        
      if(isset($_POST['ShowJP'])){  
        $showfile = $_POST['sel_files'];  
        if($showfile != ""){  
         $inhalt = file($upload . "/" . $showfile); //HIER KRACHT ES DANN  
         ...  
      
      ~~~  
        
      Gruss  
      Werner
      
      1. Hallo,

        Andere files mit 9 MB ode soagr 12 MB machen keine Probleme.

        dann solltest du uns mal -zumindest von einem technischen Standpunkt betrachtet- verraten, was das für Dateien sind.

        $inhalt = file($upload . "/" . $showfile); //HIER KRACHT ES DANN

        Ist dir klar, was file() genau tut? Es erzeugt ein Array, jedes Element entspricht einer Zeile aus der Datei. Das ergibt natürlich nur bei Textdateien einen Sinn. Ist das in deinem Fall so?

        Und falls ja: Ich weiß nicht, wie effizient (hier: speichersparend) file() arbeitet. Aber wenn eine Datei überwiegend sehr kurze Zeilen enthält, wird die Speicherung als Array sehr viel mehr Platz brauchen als eben die reine Dateigröße.

        Ciao,
         Martin

        --
        Der geistige Horizont ist der Abstand zwischen Brett und Hirn.
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
        1. HAllo Werner,

          dann solltest du uns mal -zumindest von einem technischen Standpunkt betrachtet- verraten, was das für Dateien sind.

          Kann alles Mögliche sein. Aufgetreten ist dies bei einer PDF Datei und einer POstscript Druckdatei.

          Ist dir klar, was file() genau tut? Es erzeugt ein Array....

          ja das ist / war mir klar.
          Allerdings liegt hier vermutlich auch der Knackpunkt. Wenn ich die anstatt mit file() mit fopen arbeite, bekomme ich keine Probleme.

            
          $fh = fopen($upload . "/" . $myfile,'r');  
          if($fh){  
          for ($i=0;$i<50;$i++){  
          $inhalt[] = fread($fh,4096);  
          }  
          }  
          
          

          Es muss also doch irgendwie am Dateiinhalt und am einlesen als Array liegen.

          Die Frage wäre auch, wie man das Problem mit file() abfangen kann. Denn selbst wenn man vorher mit filesize() die Größe prüft, wäre das ja ok, weil das PHP Memorylimit ja bei 50 MB liegt und die Datei selbst nur 9 MB hat.

          Gruss
          Werner

          1. Hi,

            HAllo Werner,

            nanu, du sprichst *mich* mit Werner an? ;-)

            dann solltest du uns mal -zumindest von einem technischen Standpunkt betrachtet- verraten, was das für Dateien sind.
            Kann alles Mögliche sein. Aufgetreten ist dies bei einer PDF Datei und einer POstscript Druckdatei.

            Okay, die sind aber nicht zeilenorientiert, so dass file() hier keinen Sinn ergibt.

            Ist dir klar, was file() genau tut? Es erzeugt ein Array....
            ja das ist / war mir klar.

            Und trotzdem lässt du es auf beliebige, nicht zeilenweise organisierte Dateien los?
            Warum verwendest du überhaupt file()? Was hast du mit dem Dateiinhalt vor?

            Möglicherweise ist file_get_contents() für dich günstiger. Ob es überhaupt nötig ist, die Datei komplett im Arbeitsspeicher vorzuhalten, ist noch eine ganz andere Frage.

            So long,
             Martin

            --
            Ein Patriot ist jemand, der bereit ist, sein Land gegen seine Regierung zu verteidigen.
            Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
            1. Hallo Martin :-))

              Und trotzdem lässt du es auf beliebige, nicht zeilenweise organisierte Dateien los?
              Warum verwendest du überhaupt file()? Was hast du mit dem Dateiinhalt vor?

              Möglicherweise ist file_get_contents() für dich günstiger. Ob es überhaupt nötig ist, die Datei komplett im Arbeitsspeicher vorzuhalten, ist noch eine ganz andere Frage.

              ja da hast du Recht. Im nachhinein war / ist das Quatsch. Denn ich brauche eigentlich hier in dem konkreten Fall nur die ersten 50 Zeilen, weil ich später nach einem bestimmten Vorkommen von Zeichen prüfen möchte.

              Gibt es denn noch eine "bessere", saubere Methode oder etwas was weniger Ressourcen braucht als mit fopen...

              $fh = fopen($upload . "/" . $myfile,'r');
              if($fh){
              for ($i=0;$i<50;$i++){
              $inhalt[] = fread($fh,4096);
              }
              }

              Gruss
              Werner

              1. Tach!

                Denn ich brauche eigentlich hier in dem konkreten Fall nur die ersten 50 Zeilen, weil ich später nach einem bestimmten Vorkommen von Zeichen prüfen möchte.
                Gibt es denn noch eine "bessere", saubere Methode oder etwas was weniger Ressourcen braucht als mit fopen...

                fopen(), direkt die Zeile verarbeiten und nach 50 Zeilen abbrechen, ist schon effizient genug. Aber nimm nicht das allgemeine fread() sondern das zeilenbasierte fgets().

                dedlfix.

                1. Denn ich brauche eigentlich hier in dem konkreten Fall nur die ersten 50 Zeilen, weil ich später nach einem bestimmten Vorkommen von Zeichen prüfen möchte.
                  Gibt es denn noch eine "bessere", saubere Methode oder etwas was weniger Ressourcen braucht als mit fopen...

                  Einfach mal ungetestet in den Raum geworfen...
                  Eventuell funktioniert in deinem Fall auch parse_url, fsockopen, fwrite, stream_set_timeout und besonders fread mit zweitem Parameter.

                  Hier mal ein Ausschnitt eines Scripts von mir.

                    
                  $this->strRequestUrl = 'https://www.domain.tld/your.file';  
                  $arrParsedUrl = parse_url($this->strRequestUrl);  
                  if(!$resSocket = @fsockopen('ssl://'.$arrParsedUrl['host'], 443, $intErr, $strErr, 5)){  
                  	$this->strError = 'failed to establish a connection to "'.$this->strRequestUrl.'" [ '.$intErr.', '.$strErr.' ]';  
                  	throw new Exception($this->strError);  
                  }  
                  $strHeader = 'GET '.$arrParsedUrl['path'].'?'.$arrParsedUrl['query'].' HTTP/1.1'.CRLF.'Host: '.$arrParsedUrl['host'].CRLF.'Connection: Close'.CRLF.CRLF;  
                  fwrite($resSocket, $strHeader);  
                  stream_set_timeout($resSocket, 5);  
                  		  
                  do{  
                  	if(strlen($strInput = fread($resSocket,1024))==0){  
                  		break;  
                  	}  
                  	$this->strRawData .= $strInput;  
                  }while(true);
                  

                  Grüße, Matze

        2. Und falls ja: Ich weiß nicht, wie effizient (hier: speichersparend) file() arbeitet. Aber wenn eine Datei überwiegend sehr kurze Zeilen enthält, wird die Speicherung als Array sehr viel mehr Platz brauchen als eben die reine Dateigröße.

          Ein PHP-Arrayelement benötigt 144 Byte Speicherplatz. Bei Strings zusätzlich noch den Speicher für die Bytes dieses Strings (Integer, Floats oder Booleans sind in den 144 Byte schon enthalten).

          Obendrauf kommt noch Overhead für das Array selbst, sowie ein wenig Platz für eventuell hinzukommende Elemente, die in der Hashtable schon mal reserviert, aber noch nicht gefüllt werden.

          Aus dieser Information ergibt sich, dass mit dem verfügbaren Speicher maximal 364088 Arrayelemente möglich sind - abzüglich des Platzes für die Strings der Textdatei.

          Mit anderen Worten: Wenn die Datei nur 9 MB groß ist, ist es viel schlauer, sie als String einzulesen, oder eventuell auch GAR NICHT komplett in den Speicher zu legen.

          Denn mit "SplFileObject" gibts in PHP die Möglichkeit, sich einfach ein iterierbares Objekt zu erzeugen, dass dann die Datei nach und nach durchliest, man das aber nicht explizit programmieren muss.

          Anstatt $inhalt = file($upload . "/" . $showfile); wäre der geeignete Ersatz $inhalt = new SplFileObject($upload . "/" . $showfile);

          - Sven Rautenberg

          1. Hallo!

            Denn mit "SplFileObject" gibts in PHP die Möglichkeit, sich einfach ein iterierbares Objekt zu erzeugen, dass dann die Datei nach und nach durchliest, man das aber nicht explizit programmieren muss.

            Wow, sehr schöne Angelegenheit! Gibt es dazu eventuell ein paar Codeschnipsel/Anwendungsbeispiele die du empfehlen würdest?

            Grüße, Matze

            1. Hi!

              Denn mit "SplFileObject" gibts in PHP die Möglichkeit, sich einfach ein iterierbares Objekt zu erzeugen, dass dann die Datei nach und nach durchliest, man das aber nicht explizit programmieren muss.

              Wow, sehr schöne Angelegenheit! Gibt es dazu eventuell ein paar Codeschnipsel/Anwendungsbeispiele die du empfehlen würdest?

              Schau mal ins PHP Manual - auf den Folgeseiten gibt es auch einiges unter "User Contributed Notes".

              off:PP

              --
              "You know that place between sleep and awake, the place where you can still remember dreaming?" (Tinkerbell)
              1. Hallo!

                Schau mal ins PHP Manual - auf den Folgeseiten gibt es auch einiges unter "User Contributed Notes".

                Das hatte ich natürlich schon gefunden, deshalb fragte ich extra nach "Empfehlungen".
                Hätte sein können, dass das Thema in einem empfehlenswerten Artikel irgendwo noch genauer behandelt wurde.

                Grüße, Matze

      2. Moin,

        nein da ist keine Endlosschleife drin. Wie gesagt das passiert ja nur bei diesem File. Andere files mit 9 MB ode soagr 12 MB machen keine Probleme.

        Da hilft IMHO nur debuggen. Interessant ist noch: Bist du bei einem Webspace-Provider oder hast du einen eigenen Server? Was sagt beim Abbrechen des Skriptes memory_get_usage() ?

        Wie sieht es aus, wenn du relevante Teile des Skripts nimmst, ein neues Skript baust und es dann mit derselben Datei versuchst?

        Grüße Marco

        --
        Ich spreche Spaghetticode - fließend.
        1. Tach!

          Was sagt beim Abbrechen des Skriptes memory_get_usage() ?

          Es kann dazu nichts sagen. Es ist ein fataler Fehler, der keinen nutzerdefinierten Error-Handler mehr ausführt. Man kann höchstens vor dem file() die Speicherauslastung messen.

          Wie sieht es aus, wenn du relevante Teile des Skripts nimmst, ein neues Skript baust und es dann mit derselben Datei versuchst?

          Das ist immer eine gute Idee. Beschränkt sich in dem Fall ja auf einen Einzeiler: $dummy = file(Dateiname);

          dedlfix.