Armory + PHP – Teil 1: XML einlesen, Onlinestatus, einfache Ausgabe
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.
Am 4.04.2008 von Jan in WoW/Programmierung
April 10th, 2008 at 13:17
[...] Ein Tutorial für alle Entwickler in meinem Blog: Armory + PHP – Teil 1: XML einlesen, Onlinestatus, einfache Ausgabe [...]
April 10th, 2008 at 17:48
*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%
April 11th, 2008 at 08:50
LOL, welche Sprache ist das? Ich versteh kein Wort…^^
Gnomen- oder Goblintechnik?
April 11th, 2008 at 15:28
PHP wird gesprochen
Eben ein Entwicklerpost.
April 14th, 2008 at 13:48
Hi,
echt gutes Tutorial. Sagmal, kann es sein, das mach bei zuviel Anfragen irgendwie gebannt wird?
Gruß
April 14th, 2008 at 15:27
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?
April 14th, 2008 at 18:00
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.
April 14th, 2008 at 18:03
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.
April 14th, 2008 at 18:34
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
April 14th, 2008 at 18:55
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); }
##
April 16th, 2008 at 18:37
danke für deine Antwort. Das funktioniert auch! Aber man kannkeine Deutsche Gilde auswählen -.-
April 16th, 2008 at 18:57
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
April 16th, 2008 at 19:15
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
April 16th, 2008 at 20:09
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.
April 17th, 2008 at 13:20
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?
April 17th, 2008 at 14:24
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″;
April 17th, 2008 at 15:55
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!
April 17th, 2008 at 16:39
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.
April 25th, 2008 at 08:19
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.
May 16th, 2008 at 23:54
wo bleibt teil 2?
October 31st, 2008 at 04:27
Hallo,
also erstmal, dein Script hat mir den Tag gerettet, ich kam nicht auf die Sache mit dem User Agent… Egal
Ich habe nun aber folgendes Problem, ich möchte in meiner Gilde anzeigen lassen, wer schon alles T6 trägt, dazu habe ich folgenden Code:
echo $xml->characterInfo->character['name'].” traegt folgendes T6:”;
if ($xml->characterInfo->characterTab->items->item['id'] = 31051){
$kopf = “Kopf”;
}
elseif ($xml->characterInfo->characterTab->items->item['id'] = 33285){
$haende = “Haende”;
}
echo $kopf. “”;
echo $haende. “”;
Nun ist aber das Problem, dass immer nur das erste “item['id']” ausgelesen wird, wie schaff ich es, dass der das andere auch einliest?
THX
PrimuS
November 1st, 2008 at 09:08
Funktioniert in dem Sinn von der Armory Seite schlecht. Blizzard zeigt wie gesagt nur die IDs in der Charakterübersicht an.
Mit Hilfe dieser IDs und einem weiteren kleinen XML Script kannst du dir die Daten zu Items aber z.B. von Wowhead.com holen.
http://www.wowhead.com/?item=25867&xml
Die passende ItemID setzen und Daten auslesen.
December 18th, 2008 at 21:11
Hi du,
danke für die große Hilfe hier.. hab da noch ne Frage… bei mir kommen nur die Englischen Daten an… kannst du mir sagen, wie ich den useragent oder curl einstellen muss, damit ich die deutschen xml-daten geliefert bekomme?
December 19th, 2008 at 08:55
Soweit ich informiert bin, kann man nur die englischen Daten auslesen. Blizzard übersetzt diese erst bei ihrer eigenen Ausgabe. Daten zu Items kannst du über ItemID und die XML Daten von deutschen Itemdatenbanken bekommen. Andere Werte müsstest du wie im englischen verwenden (Hitrating, AttackPower, etc).
December 21st, 2008 at 18:28
Das interessante ist ja, dass die XML-Anzeige, wenn man die Datei im BRowser direkt aufruft anhand des Browsers anscheinend die Sprache erkennt und alles in Deutsch ausgibt.
Aber nicht über den PHP-Aufruf…
sollte ich was rausfinden, melde ich mich noch mal
December 21st, 2008 at 18:35
Ok, da bin ich wieder
Geistesblitze und so weiter
Also:
man benötigt diese Variable:
$header[] = “Accept-Language: de-de,de;q=0.5″;
und dann noch diese Curl-Einstellung:
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
dann gibts Deutsche Werte
December 25th, 2008 at 03:53
Ich bekomme immer eine Reihe Fehlermeldungen bei dem Script. Hier der Link
http://www.ewguild.de/member_info.php
December 25th, 2008 at 09:17
Anscheinend ist auf deinem Webspace/Server das fopen deaktiviert / funktioniert nicht. Dem Server ist es also nicht möglich sich die Datei zu laden. Am besten Funktion aktivieren oder XML anderweitig einlesen lassen.
December 25th, 2008 at 12:47
Laut phpinfo(); ist die funktion aber aktiviert http://www.ewguild.de/info.php
December 25th, 2008 at 13:01
Jetzt scheint es zu funktionieren aber ich bekomme keine Ausgabe, habe den Code im Beispeil komplett übernommen. Habe ich irgendwas vergessen?
December 25th, 2008 at 14:41
Da musst du mir schon etwas Code zeigen bzw. Fehlermeldungen aus dem Errorlog oder der Anzeige.
http://www.rafb.net/paste/
Für den Code. Ferndiagnose nur vom hören kann ich nicht machen.
December 25th, 2008 at 15:03
Oh, ne jetzt gehts ^^. War nur ein Fehler in der URL-Übergabe
December 26th, 2008 at 23:23
Jetzt habe ich das Problem wie bekomme ich die Mitglieder aus der guild-info.xml in ein Array.
December 27th, 2008 at 09:43
Indem du dir die XML Datei anschaust mit der Blizzard arbeitet und daraus die Daten ausliest.
http://de.php.net/simple_xml – Simple_XML wird den Freund und etwas Spielerei mit Arrays/Objekten. Nicht viel anders als Charakterdaten auslesen.
January 5th, 2009 at 02:48
Hallo, ich wieder…
wer sehen will was man aus disem Denkanstoss alles machen kann sollte wich http://www.wowtiertracker.com mal anschauen… Aktuell habe ich scheinbar ein Problem mit irgendeiner Flood Protection der Armory, gibt es sowas? Wenn ich Chars nacheinander von Hand eintrage geht das alles prima, allerdings benutze ich ein Script was alle Chars einer Gilde mit einem mal erfasst, das funktioniert ein bis zwei Mal und dann gehts nicht mehr… Hat jemand eine Idee? Ich habe des weiteren ein “Update” Script, das alle 6 Stunden läuft, das wäre dann ja, sollte es einen solchen “Flood” Schutz geben bei zunehmender Größe nutzlos… Wie macht wowjutsu.com das?
LG
TorsteN
January 5th, 2009 at 09:32
Deine Seite funktioniert nicht, ich bekomm nicht raus wie ich da einen Charakter prüfe oder ich bin einfach zu blöd den richtigen Knopf zu finden.
Nichtsdestotrotz kannst du dir mal die PHP Funktion sleep(); anschauen. Bei meiner Gilden- / Arenateamfunktion habe ich die mit dazwischengebaut um das übermäßige flooden zu vermeiden. Seit dem hat es auch mit großen (extrem großen) Datenmengen funktioniert (100.000+ Chars).
January 10th, 2009 at 21:51
Hi Jan,
dein Kommentar bezüglich dem User-Agent hat mir sehr geholfen! Ich war schon fast am Verzweifeln!
Grüße
Michael
February 15th, 2009 at 00:02
Hallo Jan,
ich habe das mit dem sleep getestet, aber ich kann nicht sagen ob das funktioniert, ich bekomme einen Internal Server Error (500), ich vermute das liegt daran, dass die Abfrage zu lange dauert, ich habe das mit sleep(10) und sleep(5) probiert, erfolglos. Liegt das an meinem Anbieter?
Dankööö für die Hilfe
TorsteN
PS: Was war denn nicht zu finden?
April 21st, 2009 at 13:19
Hi Jan,
ich raff das nich so richtig.
wenn ich damit versuch ne Gilde auszulesen bekomm ich nix zurück.
Mach ich was falsch ?
oder Bin ich blind?
http://rafb.net/p/5gt4Nf83.html
Ciao lex
June 23rd, 2009 at 06:51
Bekomme auch dauernd diesen nervigen 500er Fehler. In den Logs nichts auffälliges.
Auf nem anderen Server lief das Script einwandfrei. Settings sind nahezu gleich….maaaan!
July 14th, 2009 at 19:59
[...] Hoffentlich gibt es noch ein paar Leser und der Blog ist nicht vollkommen vergessen! Besteht eigentlich noch Interesse an einer Fortführung der Armory-Programmier-Serie? [...]
July 25th, 2009 at 03:26
Hey,
da ich in Zukunft eine Gilde plane, wollte ich gerne ein paar Dinge einbauen…u.a. eine Art Armory Überprüfung… da ich schon sehr lange PHP programmiere ist es auch kein Problem…nur kenne ich leider nicht alle Begriffe z.B. für Gilde oder Talente usw… wäre cool wenn es iwo ne Liste gäbe
MfG
July 28th, 2009 at 17:29
Danke für das Script, genial!
December 7th, 2009 at 06:27
Kleiner Tipp noch:
ini_set(”user_agent”, “Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5″);
$contextOptions = array(”http” => array (”header” => “Cookie:cookieLangId=de_DE\r\n”));
$context = stream_context_create($contextOptions);
$content = file_get_contents(”http://eu.wowarmory.com/character-sheet.xml?locale=de_de&r=Malorne&n=Killercorpse&lang=de_de&language=de_de”, false, $context);
Das setzt beim HTTP-Request nen Cookie für deutsche Sprache!
February 20th, 2010 at 15:05
Ich habe noch folgendes Problem…
hoffentlich antwortet mir jemand obwohl die letzten Posts vom Juli sind =)
Ich versuche Informationen über eine komplette Gilde aus dem Arsenal zu ziehen.
Das sind jedoch jede menge Daten, denn die komplette Gildenseite inclusive der kompletten CharacterDaten…
Hat jemand eine Idee für ‘ne Lösung?
February 20th, 2010 at 18:18
Am besten in ein großes Array werfen, nacheinander durchgehen und schauen welche Daten du brauchst.
Dürfte iterativ genauso gut funktionieren wie eine rekursive Funktion. Musst du eben schauen wieviele Daten es wirklich sind.
April 7th, 2010 at 17:44
Also bei mir funktioniert das irgendwie net…da kommt bei mir garnix raus nur nen weißes Fenster. Hab schon alles versucht aber funktioniert immernoch net. Hab auch schon in meiner phpinfo() nachgeschaut… XML, cURL etc. alles installiert auf meinem server.
June 27th, 2010 at 19:38
Sooo nachdem ich mir hier alles durchgelesen habe und trotzdem als php unwissender nicht weiter komme habe ich die frage ob es einen komplett fertigen script gibt.
Versuche mich auch gerade an einer Gildenhomepage über NetObjects Fusion 11 und möchte da auch die Gildenmember einfügen lassen ohne das ich die Seite jeden Tag manuel aktualisieren muss.
Da ich mich aber mit Php und so fast garnicht auskenne ist es garnicht so leicht.
Wäre nett wenn mir da jemand hilft.
MfG Wulf