• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Dateiproblem

Kalibo

Neues Mitglied
Hi Leute

Ich hab ein Problem. Ich hole mir von einem Server eine Grafikdatei (PNG) und speichere sie auf meinen Server. So verhindere ich, dass jeder benutzer die Datei wiederum auf dem Fremdserver anfordert sondern die datei direkt auf meinem Server zur verfügung steht. Da die Datei aber aktuell sein soll, möchte ich sie alle 8 Sekunden updaten. Was meine Klasse auch prima hinkriegt. Ich bekomme aber beim Zugriff mehrerer Benutzer ab und zu die Fehlermeldung:

Warning: imagecreatefrompng() [function.imagecreatefrompng.php]: gd-png: fatal libpng error: IDAT: CRC error
Warning: imagecreatefrompng() [function.imagecreatefrompng.php]: gd-png error: setjmp returns error condition
Warning: imagecreatefrompng() [function.imagecreatefrompng.php]: 'lhc1.png' is not a valid PNG file
Warning: imagecolorat(): supplied argument is not a valid Image resource
...

Ich nehme an, dass dies mit dem gleichzeitigen lesen während ein anderer Benutzer schreibt zu tun hat... Habe versucht verschiedene prüfungen einzubauen. der fehler kommt jedoch trotzdem noch...

jemand eine ahnung?

hier meine Klasse:

Danke Gilles für deinen Hinweis. Hier also nochmals der PHP Code.

PHP:
<?php
class CernGraph {

    // Anlegen der Instanz
    private static $instance = NULL;
    private static $URL = 'http://vistar-capture.web.cern.ch/vistar-capture/';
    
    // Konstruktor private, damit die Klasse nur aus sich selbst heraus instanziiert werden kann.
    private function __construct() {}
    
    // Diese statische Methode gibt die Instanz zurueck.
    public static function getInstance() {

        if (self::$instance === NULL) {
            self::$instance = new self;
        }
        return self::$instance;
    }

    public function getCernGraph($filename){

    }

    public function getFile($filename)
    {
        $diff = (time()-filemtime($filename));
        //echo "diff:$diff<br/>";
        if($diff>8){
            //echo 'grösser 8<br/>';
            self::updateFile('lhc1.png');
        }
        if (is_readable($filename)) {
            try {
                return ImageCreateFromPNG($filename);
            } catch (Exception $e){
                sleep(1);
                return self::getFile($filename);
            }
        } else {
            sleep(1);
            return self::getFile($filename);
        }
    }
    

    private function updateFile($filename)
    {
        if(!is_writable($filename)){
            return;
        }
        //echo "start update file<br/>";
        $url = self::$URL.$filename;
        //echo "updateFile:url:$url<br/>";
        $file = explode("/", $url);
        ob_start();
        $fp = fopen($url, "r");
        fpassthru($fp);
        fclose($fp);
        $file = ob_get_contents();
        ob_end_clean();
        $savepath = ''; //Speicherpfad anpassen, Ordnerrechte nicht vergessen!!
        if (file_exists($savepath.$filename))
        unlink($savepath.$filename);
        $fp = fopen($savepath.$filename, "a");
        fwrite($fp, $file);
        fclose($fp);
        //echo "end update file<br/>";
    }
    
    // Klonen per 'clone()' von außen verbieten.
    private function __clone() {}
}

?>


danke.

Das 8) soll 8 ) heissen.
 
Zuletzt bearbeitet von einem Moderator:
Werbung:
Werbung:
mmhh.. nun das denke ich nicht. darf ich rasch erklären was ich denn genau machen möchte.. vielleicht ergibt das dann mehr sinn. erstmal, ich komme aus der java welt. arbeite mit jboss und tomcat etc.

wie oben beschrieben greife ich alle 8 sekunden auf das dateisystem meines servers zu und erstelle eine neue datei. nun wenn nun eine session kommt und dies auslöst benötigt folgende funktion einige millisekunden um dies zu erledigen:

PHP:
private function updateFile($filename) 
    { 
        if(!is_writable($filename)){ 
            return; 
        } 
        //echo "start update file<br/>"; 
        $url = self::$URL.$filename; 
        //echo "updateFile:url:$url<br/>"; 
        $file = explode("/", $url); 
        ob_start(); 
        $fp = fopen($url, "r"); 
        fpassthru($fp); 
        fclose($fp); 
        $file = ob_get_contents(); 
        ob_end_clean(); 
        $savepath = ''; //Speicherpfad anpassen, Ordnerrechte nicht vergessen!! 
        if (file_exists($savepath.$filename)) 
        unlink($savepath.$filename); 
        $fp = fopen($savepath.$filename, "a"); 
        fwrite($fp, $file); 
        fclose($fp); 
        //echo "end update file<br/>"; 
    }

Nun, während die eine session diese operation anstösst könnte es vorkommen, dass währendessen eine zweite session auch das bedürfnis hat diese operation anzustossen, da die entscheidung dazu hier geregelt wird:

PHP:
$diff = (time()-filemtime($filename)); 
        //echo "diff:$diff<br/>"; 
        if($diff>8){ 
            //echo 'grösser 8<br/>'; 
            self::updateFile('lhc1.png'); 
        }

also die entscheidung liegt dem datum der datei zugrunde.

nun passiert es, dass aber die zweite session nun der ersten folgt, dies jedoch aber völlig unnötig ist, da ein update des files pro 8 sekunden völlig ausreicht. was ich bräuchte ist eine lupensichere verarbeitung des files was mir aber nicht gelingt. als alternative dazu wollte ich ein cronjob aufsetzen, jedoch würde dieser die datei lediglich alle minuten updaten.. das ist mir zu langsam.

was ich also bräuchte ist ein mechanismus, welcher es erlaubt ein server globales zeichen zu setzen, damit weitere sessions nicht auch das file updaten. bei java überigens kein problem..

übrigens.. früher hatte ich es so implementiert, dass jede session einfach das file für sich remote bezieht.. aber als meine seite in kurzer zeit über 600'000 hits hatte.. lag der server meines providers niedergeschlagen am boden zerstört :)..

nun, wie gesagt, vielleicht gehe ich auch einen völlig falschen weg.. wäre dankbar um aufklärung.

cheers
 
Die einfachste Variante die mir einfällt ist, die Datei am Anfang des updateFile() mit einer exklusiven Zugriffssperre zu versehen und diese erst am Ende von updateFile() wieder aufzuheben. Dazu bietet sich PHP: flock - Manual an.

Ansonsten könnte ich mir eine Umsetzung als Daemon mithilfe von PHP: Libevent - Manual vorstellen.
 
Werbung:
*seufz* Aus Versehen beim Editieren den Text gelöscht.

Also, ich habe die Klasse etwas umgeschrieben, weil mir 4, 5 Dinge nicht gefielen. Ist aber natürlich bloß ein Vorschlag. Das Locking habe ich über eine "lock"-Datei implementiert, die existiert, so lange das Script mit Dateioperationen beschäftigt ist. (Nicht intensiv getestet.)

Das Error-Handling mit @ ist sehr unschön, da Fehler lediglich unterdrückt werden. Es gibt eine Möglichkeit, auch PHP-Standardfehler in Exceptions "umzuwandeln", aber die habe ich gerade nicht im Kopf.

PHP:
<?php

/**
 *
 */
class CernGraph
{
    /**
     * Instanz
     *
     * @var CernGraph
     */
    protected static $_instance = null;

    /**
     *
     * @var string
     */
    protected $_url = 'http://vistar-capture.web.cern.ch/vistar-capture/';

    /**
     * Speicherpfad anpassen, Ordnerrechte nicht vergessen!!
     *
     * @var string
     */
    protected $_savePath = './save';

    /**
     *
     * @var string
     */
    protected $_lockFile = './save/lock';

    /**
     *
     * @var int
     */
    protected $_refreshInterval = 8;

    /**
     *
     * @var int
     */
    protected $_maxRetries = 10;

    /**
     * Konstruktor private, damit die Klasse nur aus sich selbst heraus
     * instanziiert werden kann.
     */
    protected function __construct() {}

    /**
     * Diese statische Methode gibt die Instanz zurueck.
     *
     * @return CernGraph
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    /**
     *
     * @param <type> $filename
     */
    public function getCernGraph($filename) {}

    /**
     *
     * @param string $filename
     * @return bool|resource
     */
    public function getFile($filename)
    {
        $test     = false;
        $cnt      = $this->_maxRetries;
        $filepath = $this->_savePath . '/' . $filename;

        while ($test === false && $cnt > 0) {
            if (!file_exists($this->_lockFile)                
                && (
                    !file_exists($filepath)
                    || (time() - filemtime($filepath)) > $this->_refreshInterval
                )
            ) {
                $this->_updateFile($filename);
            }

            $test = @imagecreatefrompng($filepath);

            if ($test === false) {
                sleep(1);
            }

            $cnt--;
        }

        return $test;
    }

    /**
     *
     * @param string $filename
     */
    protected function _updateFile($filename)
    {
        // Set lock
        touch($this->_lockFile);

        $filepath = $this->_savePath . '/' . $filename;

        $data = @file_get_contents($this->_url . $filename);

        if ($data !== false) {
            @file_put_contents($filepath, $data);
        }

        unset($data);

        // Remove lock
        unlink($this->_lockFile);
    }

    /**
     * Klonen per 'clone()' von außen verbieten.
     */
    protected function __clone() {}
}



$c = CernGraph::getInstance();

$res = $c->getFile('lhc1.png');

if ($res !== false) {
    header('Content-type: image/png');
    imagepng($res);
} else {
    echo 'error';
}
 
Zuletzt bearbeitet:
Zurück
Oben