blog.skyfighter.net
world of warcraft blog

Armory + PHP - Teil 1: XML einlesen, Onlinestatus, einfache Ausgabe

04.04.2008 by Jan

Die Informationsvielfalt im Armory ist recht gigantisch und wird auch grafisch hochwertig präsentiert. Leider fehlt jegliche direkte Entwicklerschnittstelle und nicht jeder kann sich mit derart übertriebenen Darstellungen anfreunden. Der Vorteil im Armory liegt in seinem Datenhintergrund. Es generiert sich aus XML-Dateien, welche mit relativ wenig Mühe in PHP eingelesen werden können.

Der UserAgent und das Täuschungsmanöver

Blizzard rückt seine Daten nicht sofort heraus, sondern man muss die Scriptabfrage als Benutzeranfrage verschleiern um die XML-Datei im Hintergrund laden zu können. In PHP wird die ini-Funktion “user_agent” dafür verwendet und die Ausgabe nach UTF-8 formatiert.

# UserAgent setzen
$useragent = "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) 
Gecko/20040206 Firefox/1.0.1";
ini_set('user_agent',$useragent); 
header('Content-Type: text/html; charset=utf-8');

XML-Datei einlesen

Der nächste Schritt besteht darin, die Daten der XML-Datei erstmal als Variable in die PHP-Andwendung zu bekommen, bevor wir irgendwelche Algorithmen zur Auswertung starten können.
Innerhalb meiner Armory Klasse habe ich mich für eine Variante mit CURL entschieden. Dies setzt die libcurl voraus. Der Useragent wird auch hier bei der Anfrage übergeben. Ein einfacher Weg ist auch die XML-Datei mittels file_get_contents() in eine Stringvariable zu laden.

# URL vorbereiten
$URL 
= "http://eu.wowarmory.com/character-sheet.xml?r=Echsenkessel&n=Ariliao";
 
# CURL initialisieren und XML-Datei laden
$curl = curl_init();
 
curl_setopt ($curl, CURLOPT_URL, $URL);
curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 
$load = curl_exec($curl);
curl_close($curl);

Armory online oder offline?

Aufgrund der extrem starken Auslastungen kann es vorkommen, dass das Armory nicht erreichbar ist. Meist wird eine Standardnachricht angezeigt und man erhält keinen Einblick auf Daten.

Nach einiger Tüftelei kann die Länge des eingelesenen Strings (im Onlinefall die XML-Datei) dazu benutzt werden einen Status relativ zielsicher zu ermitteln. Die Übersicht eines Charakters ist bis zu 15.000 Zeichen lang und im Gegensatz zur Fehlermeldung wesentlich größer. Eine Überprüfung auf 5000 Zeichen Mindestlänge kann einige Probleme lösen. Wird keine Onlineabfrage durchgeführt, erhält man im Offlinefall nur wirre Datenausgaben bzw. Fehlermeldungen. Kein Benutzer des Scripts sieht so etwas gern.

# Laenge des eingelesenen Strings ermitteln
$sleng = strlen($load);
 
# Pruefen ob online / offline mittels Laenge
if($sleng >= 5000) {
 
     # Armory online => Datenverarbeitung beginnen
}
else {
 
     # Armory offline => Fehlermeldung anzeigen
}

XML-Daten nutzen => SimpleXML

PHP liefert die Möglichkeit XML-Dateien mit SimpleXML zu verarbeiten. Dabei wird der eingelesene String zu verwaltbaren XML-Elementen welche im Programmcode genutzt werden können.

# eingelesenen String zu SimpleXMLElement umformen
$xml = new SimpleXMLElement($load);

XML-Struktur und der Zugriff auf Felder und Attribute

Eine weitere Hürde für die Nutzung der Armorydaten ist die Struktur, welche im momentanen Programmcode vorliegt. Die Variable $xml enthält alle verfügbaren Charakterdaten und müssen nur noch verarbeitet werden. Eine größere Liste über die Objekte und die Form des XML-Objekts wird es in einem späteren Teil geben.

Für die momentane Ausgabe, soll nur der Name und das Level eines Charakters per echo verkündet werden. Beides befindet sich unter $xml->characterInfo->character mit dem Attribut ‘name’ bzw. ‘level’.

# Namen und Level des eingelesenen Charakters ausgeben
 
echo $xml->characterInfo->character['name']." hat das 
Level ".$xml->characterInfo->character['level'];

Probleme bei der Zuweisung in Variablen / Arrays

Die Variable $xml enthält Objekte und bei diesen kann es innerhalb von PHP zu Problemen kommen, wenn man sie einfach in neue Arrays sortieren möchte.
Ein kleiner und sicher nicht sehr eleganter Workaround ist die Zuweisung als Ergänzung zum String im Array. Bei einer Neuzuweisung ist das Ergebnis dieser ‘Ergänzung’ gleich der normalen Zuweisung, da neue Arrayfelder immer Leer sind.

# Charakternamen in neues Array bringen: ' .= ' ist die Ergaenzung
 
$Char["Info"]["name"] .= $xml->characterInfo->character['name'];

Der gesamte Quellcode des Beispiels

# UserAgent setzen
$useragent = "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) 
Gecko/20040206 Firefox/1.0.1";
ini_set('user_agent',$useragent); 
header('Content-Type: text/html; charset=utf-8');
 
 
# URL vorbereiten
$URL 
= "http://eu.wowarmory.com/character-sheet.xml?r=Echsenkessel&n=Ariliao";
 
# CURL initialisieren und XML-Datei laden
$curl = curl_init();
 
curl_setopt ($curl, CURLOPT_URL, $URL);
curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 
$load = curl_exec($curl);
 
curl_close($curl);
 
# eingelesenen String zu SimpleXMLElement umformen
$xml = new SimpleXMLElement($load);
 
# Namen und Level des eingelesenen Charakters ausgeben
 
echo $xml->characterInfo->character['name']." hat das 
Level ".$xml->characterInfo->character['level'];

Wird es noch mehr Entwicklerinfos zum Armory von dir geben?

Ja wird es. Ich plane eine Übersicht über die Datenstrukturen als Hilfe für mich wie für andere Entwickler zu veröffentlichen. Eventuell kann ich sogar Teile meiner Armory Klasse, welche auf wow.skyfighter.net zum Einsatz kommt zur Verfügung stellen.

Abgelegt in WoW/Programmierung

20 Responses

  1. WoW Armory Statistic - Charaktervergleich

    [...] Ein Tutorial für alle Entwickler in meinem Blog: Armory + PHP - Teil 1: XML einlesen, Onlinestatus, einfache Ausgabe [...]

  2. Calaelen

    *VOLL ERSCHROCKEN*

    bin vom RSS Reader auf die Seite gekommen um ein Kommentar zu hinterlassen.

    Neues Seitenlayout, sieht klasse aus. Aber wie Kaffee in einem Cola-Glas: unerwartet :p

    Zum Beitrag: Supi! *daumen hoch* Mehr davon…
    Die Zielgruppe für solche Beiträge ist sicherlich sehr klein, aber bei mir als PHP Programmierer und WoW Nerd passt es 100%

  3. Nimbert

    LOL, welche Sprache ist das? Ich versteh kein Wort…^^

    Gnomen- oder Goblintechnik?

  4. Jan

    PHP wird gesprochen ;) Eben ein Entwicklerpost.

  5. Nils

    Hi,

    echt gutes Tutorial. Sagmal, kann es sein, das mach bei zuviel Anfragen irgendwie gebannt wird?

    Gruß

  6. Jan

    Hatte ich bisher noch nicht, meine Probleme bei zuvielen Anfragen lagen eher in der Antwortzeit des Armory.

    Wenn du aber in deine Abfrageschleifen ein sleep(1) einbaust, dürfte es keine Probleme geben.

    Bei wievielen Abfragen hattest du denn Probleme?

  7. Nils

    eigentlich eine anfrage pro woche. Ich lese per script die armory aus um die Gildendaten in eine DB zu schrieben.

    Die Seite existiert und funktioniert (jetzt gerade)

    http://eu.wowarmory.com/guild-info.xml?r=Eredar&n=nRage&p=1

    Aber wenn ich per Script die abrufen will:

    “http://eu.wowarmory.com/guild-info.xml?r=Eredar&n=nRage&p=1
    Es konnte keine Verbindung mit der Blizzard Armory hergestellt werden. Bitte versuche es später erneut”

    Einmal hatte es funktioniert.

  8. Nils

    Nachtrag:

    ini_set(’user_agent’, “Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8) Gecko/20051111 Firefox/1.5″);

    echo “http://eu.wowarmory.com/guild-info.xml?r=$realm&n=$guild&p=1″;
    $url = @file_get_contents(”http://eu.wowarmory.com/guild-info.xml?r=$realm&n=$guild&p=1″);
    if (false == $url)
    {
    die (’Es konnte keine Verbindung mit der Blizzard Armory hergestellt werden. Bitte versuche es später erneut’);
    }

    ich mach das per file_get_contents.

  9. Nils

    und ohne @ kommt das hier raus:

    Warning: file_get_contents(http://eu.wowarmory.com/guild-info.xml?r=Eredar&n=nRage&p=1) [function.file-get-contents]: failed to open stream: Connection timed out in /parser.php on line 56

  10. Jan

    Also das europäische Armory ist offline bzw. reagiert nur sehr sporadisch auf Anfragen. Probiere deine Scripte am besten mit Gilden aus dem wowarmory.com (Amerikanischen Armory) aus.

    Deine if-Abfrage ist ziemlich.. blöd. Aber egal.

    Habe dein Scriptstück eben getestet mit einer US-Gilde und es funktioniert. Wichtig ist auch, dass wenn du die XML-Daten ausließt und dann anzeigen möchtest, du das am besten per:

    htmlspecialchars($url);

    machst. Ansonsten wird der ausgelesene XML-Teil nur im Quelltext sichtbar.

    Folgender Beispielcode läuft eiwandfrei und sollte dir zum testen reichen:

    ##
    ini_set(’user_agent’, “Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8) Gecko/20051111 Firefox/1.5″);

    $url = file_get_contents(”http://www.wowarmory.com/#guild-info.xml?r=Daggerspine&n=Impulse&p=1″);
    if (empty($url))
    {
    echo “Es konnte keine Verbindung mit der Blizzard Armory hergestellt werden. Bitte versuche es später erneut”;
    }
    else { echo htmlspecialchars($url); }
    ##

  11. Nils

    danke für deine Antwort. Das funktioniert auch! Aber man kannkeine Deutsche Gilde auswählen -.-

  12. Jan

    Ja, aber du kannst Abfragen über das europäische Armory am besten Nachts laufen lassen. Dann ist es meistens online und verfügbar.

    Die Datenstruktur des Armory ist nicht gerade Ladefreundlich und Ressourcenschonend von Blizzard gemacht worden. :p

  13. Nils

    hm, meinst du, die schalten die Abfragen für server ab? Weil die Items kann ich superschnell abfragen: http://eu.wowarmory.com/item-tooltip.xml?i=33682

    Aso: Die Items kann ich per Tooltip auch nicht abholen :P

  14. Jan

    Nein glaube nicht das die Abfrageserver abschalten. Aber vielleicht laufen Charaktere und Items auf getrennten Server(pools) und die Charaktere sind in Europa anscheinend generell überlastet.

    Zeig mir deine Scripte, wenn du sie fertig/ansehnlich hast.

    http://wow.skyfighter.net/EU/Echsenkessel/Ariliao

    So schaut es momentan bei mir aus.

  15. Tobi

    Sag mal, bei mir kommt wenn ich den Beispielcode ausführe:

    Bad Request

    Your browser sent a request that this server could not understand.
    Request header field is missing ‘:’ separator.

    Gecko/20040206 Firefox/1.0.1

    Fatal error: Cannot instantiate non-existent class: simplexmlelement

    Woran kann das liegen?

  16. Jan

    Ich habe aus Anzeigegründen hier im Blog einen Zeilenumbruch zwischen

    # UserAgent setzen
    $useragent = “Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6)

    und

    Gecko/20040206 Firefox/1.0.1″;

    gemacht.
    Das alles zu einer Zeile zusammeführen dann klappt es.

    # UserAgent setzen
    $useragent = “Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040206 Firefox/1.0.1″;

  17. Tobi

    Grr.. blöd das man das so mit PHP4.4.1 nicht machen kann, leider ist simplexml erst ab PHP5.0 dabei. Hab dein Script mal für diejenigen (wie mich) vereinfacht, bzw. die Abhängigkeit der libcurl entfernt. Klapp genau so :

    ini_set(”user_agent”,”Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6″);
    $xml = simplexml_load_file(”http://eu.wowarmory.com/character-sheet.xml?r=Echsenkessel&n=Ariliao”);
    echo $xml->characterInfo->character['name'].” hat das
    Level “.$xml->characterInfo->character['level'];

    Muss mich jetzt nur noch rumärgern mit doppelten einträgen wie beim Beruf, dort wir ja 2x key als Parameter angegeben. Mal sehen was draus wird, ich werde dann aber schreiben wie es läuft!

  18. Jan

    Ja mit der simplexml_load_file() kannst du die Daten auch heranholen, oder wie oben beschrieben zuerst per file_get_contents() laden und danach transformieren.

    Ich bin inzwischen etwas umgestiegen was meine XML Verarbeitung angeht und lese momentan die gesamten Teile der Armory XML automatisiert aus. Sobald ich die etwas debugged habe, werde ich sie releasen.

  19. kasperlitheater

    Ich habe versucht ein Projekt ins Leben zu rufen, welches PHP5 Libraries für den Zugriff auf die Armory bereit stellt.

    Leider aufgrund von Mangelnden Interesse wieder eingestampft:

    http://code.google.com/p/libarmory/

    Und alleine ist mir das auch zuviel Arbeit gewesen.

  20. armor

    wo bleibt teil 2?

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.