Funktion bewerten/kritisieren
Michael
- php
Guten Abend!
Ich hoffe das wird nicht als Werbung verstanden aber irgendwie muss ich mich ja auch erklären ;)
Es geht um folgendes...
Ich habe für die Community des Spiels "Battlefield Heroes" ein Script geschrieben, dass die Profilseite des Spielers bzw. dessen Heroes ausliest, daraus ein Array erstellt und das dann zurück gibt um die Daten anschließend in einer Datenbank zu speichern.
Der Sinn dahinter ist ein externes Meta-Game aus den Statistiken zu entwickeln (welches Team gewinnt öfter auf welcher Map usw...).
Da das Script dann doch auf eine ganze Menge Nutzer losgelassen wird, wollte ich euch vorher bitten mir zu sagen ob ich hier völligen Quark gemacht habe oder das so akzeptabel und vor allem auch "sicher" in welcher Form auch immer ist.
Es liegt mir wirklich sehr am Herzen. Der Code ist deutsch kommentiert, das sollte helfen.
Zum Testen der Funktion könnt ihr diese ID benutzen: 193336416
Bitte benutzt auch nur diese da sie mir offiziell zum testen freigegeben wurde. Danke!
Zum testen des "false"-Rückgabewertes reicht es der Funktion irgendwelche Buchstaben als Parameter zu geben.
Danke für das Überstehen der Vorgeschichte und jetzt die (lange) Funktion:
<?PHP
###################################################
# $target = BF:H hero-id
###################################################
function get_hero($target){
// neuen curl-Handler erzeugen $ch
$ch = curl_init();
// Verbindungs-"Parameter"
curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, true);
curl_setopt($ch, CURLOPT_URL, "http://www.battlefieldheroes.com/heroes/".urlencode($target));
// Zeit bis zum timeout in Sekunden
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, '2');
// Minimale Geschwindigkeit
curl_setopt($ch, CURLOPT_LOW_SPEED_LIMIT, '5000');
// Zeit nach der unter der minimalen Geschwindigkeit abgebrochen wird in Sekunden
curl_setopt($ch, CURLOPT_LOW_SPEED_TIME, '4');
// User-Agent-String
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5");
// Daten als String senden, nicht ausgeben
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// Daten als String an $content übergeben
$content = curl_exec($ch);
// curl-Handler schließen
curl_close($ch);
##############################################################
# Daten verarbeiten
##############################################################
// DOM-Object aus Daten machen
$doc = new DOMDocument();
@$doc->loadHTML($content);
// alle divs finden - '*' für alle Elemente
$divs = $doc->getElementsByTagName('div');
// Helden-Array erstellen
$heroes = array();
for($i = 0; $i < $divs->length; ++$i){
#############################################################
# Cache-Zeit ermittlen
#############################################################
// Cache Container finden
if($divs->item($i)->getAttribute('class') == 'cache-info'){
$bold = $divs->item($i)->getElementsByTagName('b');
// bold durchlaufen
for($a = 0; $a < $bold->length; ++$a){
if($a == 2){
$next_update = $bold->item($a)->nodeValue;
$next_update = eregi_replace('h', '', $next_update);
$next_update = eregi_replace('m', '', $next_update);
}
}
}
if($divs->item($i)->getAttribute('id') == 'heroprofile'){
############################################################
# Level, Klasse und Fraktion ermitteln
############################################################
// richtige Liste finden
$ul = $divs->item($i)->getElementsByTagName('ul');
for($b = 0; $b < $ul->length; ++$b){
if($ul->item($b)->getAttribute('class') == 'stats'){
// array erweitern
$heroes['profile'] = array();
// li-Elemente finden
$listitems = $ul->item($b)->getElementsByTagName('li');
for($a = 0; $a < $listitems->length; ++$a){
// Einträge aufarbeiten (key/value split)
$arraykey = explode(' ', $listitems->item($a)->getAttribute('class'));
$keyvalue = explode('-', $listitems->item($a)->getAttribute('class'));
// Einträge in Array speichern
$heroes['profile'][$arraykey[0]] = $keyvalue[1];
}
}
}
########################################################
# Namen ermitteln
########################################################
// h2 finden
$h2 = $divs->item($i)->getElementsByTagName('h2');
for($c = 0; $c == 0; ++$c){
// Eintrag in Array speichern
$heroes['profile']['name'] = $h2->item($c)->nodeValue;
}
########################################################
# Statistik ermitteln
########################################################
// Tabelle finden
$table = $divs->item($i)->getElementsByTagName('table');
for($d = 0; $d < $table->length; ++$d){
if($table->item($d)->getAttribute('class') == 'profileinfo'){
// array erweitern
$heroes['stats'] = array();
// Zeilen in Tabelle finden und durchlaufen
$tr = $table->item($d)->getElementsByTagName('tr');
for($e = 0; $e < $tr->length; ++$e){
// Überschrift finden (z.B. ELO, K/D-ratio, Accuracy....)
$th = $tr->item($e)->getElementsByTagName('th');
// Eintrag finden (z.B. ELO, K/D-ratio, Accuracy....)
$td = $tr->item($e)->getElementsByTagName('td');
// Einträge in Array speichern
$heroes['stats'][$th->item(0)->nodeValue] = $td->item(0)->nodeValue;
}
}
}
}
}
// Wenn Helden im Array Cache-Lifetime in das Array packen
if(count($heroes) != 0){
$heroes['lifetime'] = $next_update;
// und Array zurückgeben
return $heroes;
}else{
// sonst false
return false;
}
}
?>
Ich bin für jede Kritik dankbar solange sie mir weiter hilft.
Danke, Michael
Hi there,
Ich bin für jede Kritik dankbar solange sie mir weiter hilft.
Keine Kritik, nur eine interessierte Frage: wtf??? Was bitte ist ein Curl-Handler? Und warum schreibst Du Deine DOM-Geschichten nicht einfach in Javascript? Was hat das ganze mit PHP zu tun, ausser daß Du mit PHP irgendetwas mit Curl machst, das dann etwas mit dem DOM macht??? Bahnhof (würde sich mir vermutlich auch nicht mehr erschliessen, wüsst' ich, was ""Battlefield Horses" oder wie immer das Dingens heisst, ist...;)
Hallo Klawischnigg,
wtf??? Was bitte ist ein Curl-Handler?
dieser wird von von den Funktionen curl_inir() und curl_multi_init() zurückgegeben. Es ist vom Type her resource und stellt eine Speudoabstraktion dar.
Und warum schreibst Du Deine DOM-Geschichten nicht einfach in Javascript?
Um das mittels PHP bezogene, externe Dokument durch Javascript analysieren zu lassen, müsste man den Umweg über den Spider Monkey veranstalten. Die entsprechende Erweiterung zur Anbindung ist derzeit noch in Arbeit: http://pecl.php.net/package/spidermonkey
Wie auch immer. Javascript oder PHP sind hier beide nur Mittler der Funktionalität des DOM. DOM sollte aber verwendet werden, da die einhellige Meinung der HTML-Quelltextanalyse ist, dass dieser zu komplex ist, um hierbei Reguläre Ausdrücke nutzen zu können. Daher stellt sich einfach nur die Frage des Nutzens. PHP bezieht das externe Dokument _und_ bietet DOM-Funktionalität. Warum sollte man dann noch Javascript einsetzen? DOM ist ein Interface - keine javascript-eigene Geschichte.
Was hat das ganze mit PHP zu tun, ausser daß Du mit PHP irgendetwas mit Curl machst, das dann etwas mit dem DOM macht???
Die Nutzung von PHP ist liegt hier auf der Hand. Die gewonnenen Daten sollen in eine Datenbank gesammelt werden. Javascript scheidet durch same origin policy bereits bei der Datengewinnung aus. Zu Deinem Verständnis: Der Gebrauch der cURL-Erweiterung steht hier stellvertretend für fopen('http://externe.quell/ressource'); oder fsocketopen('http://externe.quell/ressource');.
Bahnhof (würde sich mir vermutlich auch nicht mehr erschliessen, wüsst' ich, was ""Battlefield Horses" oder wie immer das Dingens heisst, ist...;)
Mag man von Gamern halten, was man will. Sie so hirnlos zu verunglimpfen, statt eine Suchmaschine zu nutzen... Ich finde Deinen Beitrag in jeder Hinsicht peinlich.
Gruß aus Berlin!
eddi
Hallo Eddi!
Mag man von Gamern halten, was man will. Sie so hirnlos zu verunglimpfen, statt eine Suchmaschine zu nutzen... Ich finde Deinen Beitrag in jeder Hinsicht peinlich.
Danke, ich wollte nicht darauf antworten, was unter anderem daran liegt, dass meine Antwort längst nicht so kompetent ausgefallen wäre.
Manchmal, aber auch nur manchmal schlagen im Internet doch noch Argumente weil man sie nicht ignorieren kann :)
Michael
Hi there,
Mag man von Gamern halten, was man will. Sie so hirnlos zu verunglimpfen, statt eine Suchmaschine zu nutzen...
Ich hab zu Computerspielen keine Meinung, ich habe lediglich um eine Erklärung für den Code gebeten. Ich kannte das nicht, weil ich leider gelegentlich für Server schreiben muss, wo noch nicht einmal PHP4 drauf ist. Wo Du da eine Verunglimpfung erkennen magst, aber sei's drum...
Ich finde Deinen Beitrag in jeder Hinsicht peinlich.
Hast Dich aber ziemlich ausgetobt, um Deiner Entrüstung Herr werden zu können...
Hallo!
Hast Dich aber ziemlich ausgetobt, um Deiner Entrüstung Herr werden zu können...
Du hättest dir alle Fragen selbst beantworten können indem du
1. nach "Battlefield Heroes" googlest (wobei die URL sogar im Script steht);
allerdings geht es ja nicht um das Spiel an und für sich, es spielt also keine Rolle
2. meinen OP genauer und die, meiner Meinung nach, sehr ausführlichen Kommentare zum Script liest und sich daraus der Grund ergibt warum ich hier mit PHP und nicht mit JS arbeite
3. unbekannte Funktionen usw. (z.B. curl) im PHP-Handbuch nachschlägst wenn du dich dafür interessierst (wenn du dich auf dem Kenntnisstand von PHP<4 bewegst wäre das sogar zu empfehlen);
die Funktionen selbst noch zu kommentieren ist überflüssig
Stattdessen kam dein Kommentar dann doch sehr oberflächlich daher.
Wenn ich ein Script kritisieren lasse erwarte ich vom Antwortenden auch Fachverstand und nicht dass ich mich für die Grundlagen serverseitiger Verarbeitung externer Daten rechtfertigen muss.
Anders als Eddi hätte man dir nicht antworten können.
Bahnhof (würde sich mir vermutlich auch nicht mehr erschliessen, wüsst' ich, was ""Battlefield Horses" oder wie immer das Dingens heisst, ist...;)
Damit hattest du allerdings vermutlich recht, deshalb erübrigt sich die Diskussion.
Michael
Hallo Michael,
<?PHP
function get_hero($target){
$ch = curl_init();
im Folgenden böte sich curl_setopt_array() auch an.
curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, true);
CURLOPT_UNRESTRICTED_AUTH ist hier völlig falsch. Du sendest keine Authentifizierung. Demzufolge ist CURLOPT_FOLLOWLOCATION Diskussionsgrundlage. Wenn der Server eine Weiterleitung vornimmt, wirst Du es nie erfahren. Dein Script folgt hier stumpf, ohne dass Du dies abfängst. Du solltest, wie weiter unten beschrieben, in der Script-Logik mindestens den HTTP-Status abfangen.
curl_setopt($ch, CURLOPT_URL, "http://www.battlefieldheroes.com/heroes/".urlencode($target));
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, '2');
curl_setopt($ch, CURLOPT_LOW_SPEED_LIMIT, '5000');
curl_setopt($ch, CURLOPT_LOW_SPEED_TIME, '4');curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5");
Dieses Script ist kein Mozilla, noch rendert es mit dem Gecko. Zum einen ist dies unnötiger Datentransfer, zum anderen könnte der Server aufgrund des alten Browsers Änderungen des Inhalts veranlassen. Was soll das also?
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
Sagen wir, die Verbindung unterschreite für länger als vier Sekunden die gesetzte Geschwindigkeitsgrenze. Für diesen Fall trifft folgende Aussage zu: ($content===true)
Prüfe also, ob $content
gefüllt ist. Allgemein ist HTTP nicht ganz ohne und Du solltest auf alles gefasst sein. Dein jetziger Scriptansatz ist nur auf eins gefasst - nähmlich alles geht gut. Davon ist nicht auszugehen. Server können überlastet sein, Admins können sich beim Umkonfigurieren vertippt haben, was zu temporären Ausfällen käme, deren Datenbank schmiert mal schnell ab - und, und, und.
Im simpelsten Fall reicht hier wirklich folgendes:
if(($content=curl_exec($ch))===false){
return(false);
}
Dennoch gebe ich zu bedenken, lieber curl_setopt($ch,CURLOPT_HEADER,true);
zu nutzen und die HTTP-Schicht ebenso zu analysieren. Ein kleines Beispiel, was den Status ermittels:
$ch=curl_init($host);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
if(($content=curl_exec($ch))===false){
curl_close($ch);
return(false);
}
list($header, $content) =explode("\r\n\r\n",$content, 2);
list($statusline) =explode("\r\n", $header , 2);
list($httpversion,$status,$rest)=explode(' ', $statusline,3);
if($status!=200){
fehlerprotokoll($header,$target);
# besser aber Du nutzt switch() und machst Einzelfallbehandlungen
}
curl_close($ch);
curl_close($ch);
##############################################################
$doc = new DOMDocument();
@$doc->loadHTML($content);
Mit @ bekommst Du nicht mal mit, wenn es zu oben beschriebenen Verbindungsfehlern kommt und $content false
ist.
$divs = $doc->getElementsByTagName('div');
$heroes = array();
for($i = 0; $i < $divs->length; ++$i){
if($divs->item($i)->getAttribute('class') == 'cache-info'){
$bold = $divs->item($i)->getElementsByTagName('b');
for($a = 0; $a < $bold->length; ++$a){
if($a == 2){
$next_update = $bold->item($a)->nodeValue;
$next_update = eregi_replace('h', '', $next_update);
$next_update = eregi_replace('m', '', $next_update);
Statt der beiden eregi_replace()-Ersetzungen reicht hier str_replace(array('h','m'),array(''),$next_update);
völlig aus. Weiter unten wirst Du auf diesen Wert zurückgreifen, nach Deinem jetzigen Ansatz kann (if($a == 2)
) die Variable _nicht_ initialisiert sein.
}
}
}
if($divs->item($i)->getAttribute('id') == 'heroprofile'){
$heroes
ist nicht initialisiert: $heroes=array();
$ul = $divs->item($i)->getElementsByTagName('ul');
for($b = 0; $b < $ul->length; ++$b){
if($ul->item($b)->getAttribute('class') == 'stats'){
$heroes['profile'] = array();
Werden mehrere Listen der Klasse 'stats' gefunden, werden bereits gefundene Werte schlichtweg überschrieben. In wieweit das aber Relevanz bekommt, weiß ich natürlich nicht.
$listitems = $ul->item($b)->getElementsByTagName('li');
for($a = 0; $a < $listitems->length; ++$a){
$arraykey = explode(' ', $listitems->item($a)->getAttribute('class'));
$keyvalue = explode('-', $listitems->item($a)->getAttribute('class'));
$heroes['profile'][$arraykey[0]] = $keyvalue[1];
}
}
}
$h2 = $divs->item($i)->getElementsByTagName('h2');
for($c = 0; $c == 0; ++$c){
$heroes['profile']['name'] = $h2->item($c)->nodeValue;
}
$table = $divs->item($i)->getElementsByTagName('table');
for($d = 0; $d < $table->length; ++$d){
if($table->item($d)->getAttribute('class') == 'profileinfo'){
$heroes['stats'] = array();
Selber Vorbehalt.
$tr = $table->item($d)->getElementsByTagName('tr');
for($e = 0; $e < $tr->length; ++$e){
$th = $tr->item($e)->getElementsByTagName('th');
$td = $tr->item($e)->getElementsByTagName('td');
$heroes['stats'][$th->item(0)->nodeValue] = $td->item(0)->nodeValue;
}
}
}
}
}
if(count($heroes) != 0){
$heroes['lifetime'] = $next_update;
Was wenn $next_update
nicht initialisiert wurde, weil kein <b> gefunden wurde?
return $heroes;
}else{
return false;
}
}
?>
Gruß aus Berlin!
eddi
Hallo Eddi!
Danke das du dir die Mühe gemacht hast!
CURLOPT_UNRESTRICTED_AUTH ist hier völlig falsch. Du sendest keine Authentifizierung. Demzufolge ist CURLOPT_FOLLOWLOCATION Diskussionsgrundlage. Wenn der Server eine Weiterleitung vornimmt, wirst Du es nie erfahren. Dein Script folgt hier stumpf, ohne dass Du dies abfängst. Du solltest, wie weiter unten beschrieben, in der Script-Logik mindestens den HTTP-Status abfangen.
Oh das CURLOPT_UNRESTRICTED_AUTH war noch aus der Zeit als ich eine Authentifizierung brauchte.
Die Authentifizierung selbst hatte ich entfernt aber da diese Zeile keinen Schaden angerichtet hat, hab ich sie wohl übersehen.
Wegen CURLOPT_FOLLOWLOCATION: Weil die Seite wohl eng mit einem Board verknüpft ist bin ich mir sehr sicher (bzw. ich weiß es), dass die Anfrage weiter geleitet wird. Das Problem ist nur, dass ich nicht weiß wie oft.
Im Idealfall nur 1 mal aber ich weiß nicht ob das so bleibt wenn die Software für das Board geupdated wird.
Deshalb dachte ich mir ich folge erstmal "stumpf" bis etwas gefunden wird.
Das war leider(?) so beabsichtigt.
Dieses Script ist kein Mozilla, noch rendert es mit dem Gecko. Zum einen ist dies unnötiger Datentransfer, zum anderen könnte der Server aufgrund des alten Browsers Änderungen des Inhalts veranlassen. Was soll das also?
Ich weiß nicht was für einen String ich senden sollte also habe ich den genommen der bei mir "funktioniert". Das war der, des Browsers.
Sagen wir, die Verbindung unterschreite für länger als vier Sekunden die gesetzte Geschwindigkeitsgrenze. Für diesen Fall trifft folgende Aussage zu:
($content===true)
Prüfe also, ob$content
gefüllt ist.
Mh ich dachte beim überschreiten/unterschreiten wäre $content === false.
Nichts desto trotz hast du recht und ich sollte $content an der Stelle abfragen um die Ausführung des restlichen Teils zu vermeiden.
Dein jetziger Scriptansatz ist nur auf eins gefasst - nähmlich alles geht gut. Davon ist nicht auszugehen. Server können überlastet sein, Admins können sich beim Umkonfigurieren vertippt haben, was zu temporären Ausfällen käme, deren Datenbank schmiert mal schnell ab - und, und, und.
In dem Fall wird auch false zurückgegeben, nur halt erst nachdem die DOM-Funktionen angelaufen sind und das Array am Ende leer ist. Das ist schon umständlich, stimmt.
(...)Dennoch gebe ich zu bedenken, lieber
curl_setopt($ch,CURLOPT_HEADER,true);
zu nutzen und die HTTP-Schicht ebenso zu analysieren. Ein kleines Beispiel, was den Status ermittels:
Das klingt sehr gut. In der Praxis interessiert mich der Status allerdings nicht wirklich. Daher reicht mir vermutlich tatsächlich schon dieser Ansatz von dir:
Im simpelsten Fall reicht hier wirklich folgendes:
if(($content=curl_exec($ch))===false){
return(false);
}
> > @$doc->loadHTML($content);
>
> Mit @ bekommst Du nicht mal mit, wenn es zu oben beschriebenen Verbindungsfehlern kommt und $content `false`{:.language-php} ist.
Ja das habe ich irgendwie nicht verstanden.
Ich krieg "das false" natürlich nur ohne das @, allerdings wirft mir das Script ohne das @ einen Fehler aus. Oder besser eine Warnung.
Wohl weil das Dokument nicht valide aber trotzdem "wohlgeformt" ist. Das ist mal eine unverständliche Beschreibung im PHP-Handbuch :(
Das ist dann wohl auch der Grund warum ich das Ergebnis erst am Ende des Scripts auswerte :/
>
> > $divs = $doc->getElementsByTagName('div');
> > $heroes = array();
> > for($i = 0; $i < $divs->length; ++$i){
> > if($divs->item($i)->getAttribute('class') == 'cache-info'){
> > $bold = $divs->item($i)->getElementsByTagName('b');
> > for($a = 0; $a < $bold->length; ++$a){
> > if($a == 2){
> > $next\_update = $bold->item($a)->nodeValue;
> > $next\_update = eregi\_replace('h', '', $next\_update);
> > $next\_update = eregi\_replace('m', '', $next\_update);
>
> Statt der beiden eregi\_replace()-Ersetzungen reicht hier `str_replace(array('h','m'),array(''),$next_update);`{:.language-php} völlig aus.
Danke sehr. Logisch.
> (...)nach Deinem jetzigen Ansatz kann (`if($a == 2)`{:.language-php}) die Variable \_nicht\_ initialisiert sein.
Wieso nicht? Wird $a nicht mit der Schleife initialisiert?
> `$heroes`{:.language-php} ist nicht initialisiert: `$heroes=array();`{:.language-php}
Das ist mir jetzt bisschen peinlich, aber initialisier ich nicht genau mit der Zeile das Array?? Wie müsste ich es machen?
> Werden mehrere Listen der Klasse 'stats' gefunden, werden bereits gefundene Werte schlichtweg überschrieben. In wieweit das aber Relevanz bekommt, weiß ich natürlich nicht.
Ich halt auch nicht, ich kann nicht voraussehen ob und wie sich die Seite ändert und man dann das Script anpassen muss.
Dasselbe gilt für die anderen betroffenen Elemente.
> > if(count($heroes) != 0){
> > $heroes['lifetime'] = $next\_update;
>
> Was wenn `$next_update`{:.language-php} nicht initialisiert wurde, weil kein <b> gefunden wurde?
Danke für den Hinweis!
Michael
Re:
Wegen CURLOPT_FOLLOWLOCATION: Weil die Seite wohl eng mit einem Board verknüpft ist bin ich mir sehr sicher (bzw. ich weiß es), dass die Anfrage weiter geleitet wird. Das Problem ist nur, dass ich nicht weiß wie oft.
Im Idealfall nur 1 mal aber ich weiß nicht ob das so bleibt wenn die Software für das Board geupdated wird.
Deshalb dachte ich mir ich folge erstmal "stumpf" bis etwas gefunden wird.
Das war leider(?) so beabsichtigt.
Es ist Deine Entscheidung. Im Sinne einer Wartung des Codes wäre es IMHO sinnvoller, Weiterleitungen zu protokollieren und bei dauerhafter Weiterleitung die eigentliche (zielführende) Adresse im Code zu verankern.
Ich weiß nicht was für einen String ich senden sollte also habe ich den genommen der bei mir "funktioniert". Das war der, des Browsers.
Versuche es mit gar keinem. Das spart Traffic.
Sagen wir, die Verbindung unterschreite für länger als vier Sekunden die gesetzte Geschwindigkeitsgrenze. Für diesen Fall trifft folgende Aussage zu:
($content===true)
Prüfe also, ob$content
gefüllt ist.
Mh ich dachte beim überschreiten/unterschreiten wäre $content === false.
Gut aufgepasst! Richtig. ;)
Nichts desto trotz hast du recht und ich sollte $content an der Stelle abfragen um die Ausführung des restlichen Teils zu vermeiden.
Dein jetziger Scriptansatz ist nur auf eins gefasst - nähmlich alles geht gut. Davon ist nicht auszugehen. Server können überlastet sein, Admins können sich beim Umkonfigurieren vertippt haben, was zu temporären Ausfällen käme, deren Datenbank schmiert mal schnell ab - und, und, und.
In dem Fall wird auch false zurückgegeben, nur halt erst nachdem die DOM-Funktionen angelaufen sind und das Array am Ende leer ist. Das ist schon umständlich, stimmt.
(...)Dennoch gebe ich zu bedenken, liebercurl_setopt($ch,CURLOPT_HEADER,true);
zu nutzen und die HTTP-Schicht ebenso zu analysieren. Ein kleines Beispiel, was den Status ermittels:
Das klingt sehr gut. In der Praxis interessiert mich der Status allerdings nicht wirklich.
Da wäre vielleicht auch denkbar, curl_error() zu nutzen und den Endnutzer Deines Webs nicht ganz dumm sterben zulassen.
(...)nach Deinem jetzigen Ansatz kann (
if($a == 2)
) die Variable _nicht_ initialisiert sein.
Wieso nicht? Wird $a nicht mit der Schleife initialisiert?
Sagen wir, dass Dokument würde sich vom DOM-Baum verändern...
Generell aber fällt mir jetzt erst auf, dass Du gleich mittels Folgendem ganz ohne Schleife auskommen solltest:
$next_update=$bold->item(2) ? $bold->item(2)->nodeValue : '';
$heroes
ist nicht initialisiert:$heroes=array();
Das ist mir jetzt bisschen peinlich, aber initialisier ich nicht genau mit der Zeile das Array?? Wie müsste ich es machen?
Das machst Du auch viel weiter oben ganz vorbildlich. Die Variable ist initialisiert. Ich habe es nur nicht gesehen; 'tschuldigung. ;)
$heroes = array();
for($i = 0; $i < $divs->length; ++$i){
if($divs->item($i)->getAttribute('id') == 'heroprofile'){
for($b = 0; $b < $ul->length; ++$b){
if($ul->item($b)->getAttribute('class') == 'stats'){
$heroes['profile'] = array();
Gruß aus Berlin!
eddi
Hallo!
Es ist Deine Entscheidung. Im Sinne einer Wartung des Codes wäre es IMHO sinnvoller, Weiterleitungen zu protokollieren und bei dauerhafter Weiterleitung die eigentliche (zielführende) Adresse im Code zu verankern.
Das ist natürlich wahr. Es dürfte wenig sinnvoll sein die Weiterleitungen "mitzunehmen" wenn man auch direkt auf die "richtige" Adresse zugreifen kann. Dabei hab ich mir offensichtlich nicht viel gedacht.
Ich weiß nicht was für einen String ich senden sollte also habe ich den genommen der bei mir "funktioniert". Das war der, des Browsers.
Versuche es mit gar keinem. Das spart Traffic.
Mh ich war eigentlich der Meinung, dass der Server ohne User-Agent-String nicht geantwortet hat oder einen Fehler meldete. Oder mit einem "Fantasie-String". Ich hatte das irgendwann mal getestet.
Wie auch immer, für den Serverbetreiber könnte es unter Umständen von Interesse sein "wer" oder "was" da auf die Daten zugreift (Auswerten der Logfiles, übermässiger Traffic usw.) sonst könnte das Script unter Umständen als bösartiger Angriff gewertet und geblockt werden.
Deshalb habe ich jetzt die Bezeichnung des kompletten Meta-Game-Scripts als User-Agent angegeben. Es funktioniert - prima :)
Das klingt sehr gut. In der Praxis interessiert mich der Status allerdings nicht wirklich.
Da wäre vielleicht auch denkbar, curl_error() zu nutzen und den Endnutzer Deines Webs nicht ganz dumm sterben zulassen.
Das ist zwar keine optimale Lösung, aber im Endeffekt reicht "geht" oder "geht nicht". Wenn die angeforderte Seite nicht erreichbar ist, kann ich sowieso nichts daran ändern, also interessiert mich der Grund auch nicht wirklich.
Vielleicht reicht es deshalb auch nur/wenigstens den Status 200 (Ok) abzufragen?
Generell aber fällt mir jetzt erst auf, dass Du gleich mittels Folgendem ganz ohne Schleife auskommen solltest:
$next_update=$bold->item(2) ? $bold->item(2)->nodeValue : '';
Jap, mir auch. Hab es entsprechend geändert. Danke!
Allerdings hab ich mich nie mit Short-Tags befasst weshalb es bei mir dann so aussieht:
$next_update = str_replace(array('h','m'),array(''), $bold->item(2)->nodeValue);
(dasselbe beim Namen mit h2)
Michael
Re:
Vielleicht reicht es deshalb auch nur/wenigstens den Status 200 (Ok) abzufragen?
In Anbetracht, dass auch eine Weiterleitung genutzt werden kann und soll, ist hier if($result===false){}
ausreichend. Wenn Du Weiterleitungen loggen solltest, dann kommst Du um den Status und gegebenenfalls rekursive Aufrufen der Funktion get_hero() nicht herum. Auch das ist jetzt wiederum Deine Entscheidung.
$next_update = str_replace(array('h','m'),array(''), $bold->item(2)->nodeValue);
(dasselbe beim Namen mit h2)
Das verkürzt das ganze gut bei gleichbleibendem Effekt. Fein :)
Gruß aus Berlin!
eddi
Hallo Eddi!
Herzlichen Dank!
Im vergleich zum OP habe ich nun insgesamt folgendes geändert:
curl_setopt_array() statt 6 curl_setopt();
Abfrage eingefügt ob der cURL-Handler ein Ergebnis zurück liefert bevor die DOM-Methoden überhaupt ausgeführt werden;
Abfrage eingefügt ob das $heroes-Array gefüllt ist _und_ eine Cache-Lifetime gefunden wurde
Auslesen der Cache-Lifetime und des "Helden"-Namens verkürzt
Abschließend möchte ich noch anmerken, dass es in der Regel natürlich durchaus sinnvoller ist den Status-Code der Übertragung genauer auszuwerten und gegenbenenfalls eine entsprechende Fehlermeldung/ einen Fehlercode zurückzugeben um diese(n) dann weiter zu verarbeiten.
In dem Fall reicht mir allerdings false
oder != false
.
Es würde sich auch anbieten den Teil mit den cURL-Funktionen in eine weitere Funktion zu packen und auszulagern. So ließe sich Eingabe und Verarbeitung wesentlich besser trennen und kontrollieren.
Vielleicht hilft dieses Beispiel mit allen Verbesserungen ja auch jemandem der in der Zukunft eine Frage zu den cURL- oder DOM-Funktionen hat. Deshalb ändere ich für "die Suche" jetzt auch mal den Titel ein bisschen :)
Nochmals herzlichen Dank!
Michael
Und die Hälfte schon wieder vergessen... xD
curl_setopt_array() statt 6 curl_setopt();
Abfrage eingefügt ob der cURL-Handler ein Ergebnis zurück liefert bevor die DOM-Methoden überhaupt ausgeführt werden;
Abfrage eingefügt ob das $heroes-Array gefüllt ist _und_ eine Cache-Lifetime gefunden wurde
Auslesen der Cache-Lifetime und des "Helden"-Namens verkürzt
"vernünftigen" User-Agent-String gesetzt
direkte Adresse verwendet um die Weiterleitung(en) zu umgehen
Michael
Hi!
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5");
Dieses Script ist kein Mozilla, noch rendert es mit dem Gecko. Zum einen ist dies unnötiger Datentransfer, zum anderen könnte der Server aufgrund des alten Browsers Änderungen des Inhalts veranlassen. Was soll das also?
Ich gebe zu bedenken, dass es manchmal Server (oder darauf laufende Software) gibt, die auf eine User-Agent-Angabe bestehen, auch wenn sie irgendeinen Phantasie-Inhalt hat und obendrein vom Protokoll her nicht zwingend gefordert ist. So sah ich es bei einer Hilfe zu einer Fehlersuche vor einiger Zeit. Ein Browser bekam die Seite ausgeliefert, ein Minimal-Request nur einen Server-Fehler. Ein hinzugefügter User-Agent beliebigen Inhalts ergab dann das gewünschte Ergebnis.
Lo!
Hallo Dedlfix,
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5");
... Was soll das also?
Ich gebe zu bedenken, dass es manchmal Server (oder darauf laufende Software) gibt, die auf eine User-Agent-Angabe bestehen, auch wenn sie irgendeinen Phantasie-Inhalt hat und obendrein vom Protokoll her nicht zwingend gefordert ist. So sah ich es bei einer Hilfe zu einer Fehlersuche vor einiger Zeit. Ein Browser bekam die Seite ausgeliefert, ein Minimal-Request nur einen Server-Fehler. Ein hinzugefügter User-Agent beliebigen Inhalts ergab dann das gewünschte Ergebnis.
das wirklich Dumme daran ist, dass viele Konfigurationsgötter schlichtweg keinen Very-Header dazu senden, was zu erheblichen Cache-Problemen führen kann. Es wird wohl noch ein paar Jahre dauern, bis HTTP in allen Fassetten durchgedrungen ist.
Gruß aus Berlin!
eddi