Sain täältä foorumilta joku aika sitten koodin luokkaan, joka hakee Wowin Armorystä XML-datan ja sen perusteella tekee taulukon hahmon tiedoista. Homma toimii hienosti, jos nimessä ei ole erikoismerkkejä (outoja kirjaimia). Jos nimessä on erikoismerkki, taulukon sisällöksi tulee
Array ( [errorhtml] => Array ( ) )
Nimi jolla virhe tulee, on Lís.
Tässä vielä koodi, jolla taulukko luodaan:
class armoryFetch { public $armoryaddr = "wowarmory.com/"; public $region = array("eu" => "eu.", "us" => "www.", "tw" => "tw.", "kr" => "kr.", ); public $armory = array( "sheet" => "character-sheet.xml", ); // Time to parse my sheets public function ParseSheet($name, $realm, $region = "eu"){ $xml = $this->FetchXML($this->armory['sheet']."?r=".$realm."&n=".$name, $this->region[$region]); $parsed = $this->xmlToArray($xml); return $parsed; } // Hey, leech some XML! public function FetchXML($site, $region){ $url = "http://".$region.$this->armoryaddr.$site; ini_set("user_agent", 'Mozilla/5.0 (Windows; U; Windows NT 5.1; fi; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1'); $f = @fopen($url, "rb"); if($f){ $cont = stream_get_contents($f); fclose($f); } return ($cont !== false) ? $cont : ""; } // Parses XML data into an easy-to-use array public function & xmlToArray($xmlData, $includeTopTag = false, $lowerCaseTags = true){ $xmlArray = array(); $parser = xml_parser_create(); xml_parse_into_struct($parser, $xmlData, $vals, $index); xml_parser_free($parser); $temp = $depth = array(); foreach ($vals as $value) { switch ($value['type']) { case 'open': case 'complete': array_push($depth, $value['tag']); $p = join('::', $depth); if ($lowerCaseTags) { $p = strtolower($p); if (is_array($value['attributes'])) $value['attributes'] = array_change_key_case($value['attributes']); } $data = ( isset($value['attributes']) ? array($value['attributes']) : array()); $data = ( trim($value['value']) ? array_merge($data, array($value['value'])) : $data); if (isset($temp[$p])) $temp[$p] = array_merge($temp[$p], $data); else $temp[$p] = $data; if ($value['type']=='complete') array_pop($depth); break; case 'close': array_pop($depth); break; } } if (!$includeTopTag) unset($temp["page"]); foreach ($temp as $key => $value) { if (count($value)==1) { $value = reset($value); } $levels = explode('::', $key); $num_levels = count($levels); if ($num_levels==1) { $xmlArray[$levels[0]] = $value; } else { $pointer = &$xmlArray; for ($i=0; $i<$num_levels; $i++) { if ( !isset( $pointer[$levels[$i]] ) ) { $pointer[$levels[$i]] = array(); } $pointer = &$pointer[$levels[$i]]; } $pointer = $value; } } return ($includeTopTag ? $xmlArray : reset($xmlArray)); } } $parser = new armoryFetch; $parsed = $parser->ParseSheet($char, $realm); // Tämän taulukon sisällöksi tulee siis tuo error.
Joka paikassa (php-skripti, html-head sekä tietokanta) pitäisi olla sama merkistökoodaus (UTF-8).
EDIT: phpmyadmin näyttää, että tietokannassa hahmon nimi olisi "LÃs".
Voitko laittaa linkin johonkin esimerkki XML-tiedostoon, johon tuo linkittää? Saisi edes tietää raakadatan, mistä lähteä liikkeelle ja pystyy tekemään päätelmiä siitä, miten merkistöt kulkeutuvat.
http://eu.wowarmory.com/character-sheet.xml?r=The Maelstrom&cn=Lís tuossa linkki. Tulostan tuon saman nimen toisaalla olevaan listaan, jossa nimi näkyy oikein. Samaten näkyi oikein kun tulostin datat hakevassa php-tiedostossa, juuri ennen armoryFetch-luokan luomista.
Tosiaan tietokanta on UTF-8, kuten myös kaikki skriptit, jolla nimeä tulostetaan / käytetään / lisätään.
Mitä $xml-muuttuja sisältää ennen syöttöä xmlToArray-funktioon? Tuleeko virhesivu vai oikea sivu?
Eipä näytä tulostavan mitään, eli ongelma on siis FetchXML-funktion sisällä.
En vaan löydä mitään mahdollisuutta vaikuttaa fopen/stream_get_contents -funktioiden merkistökoodaukseen.
Edit: stream_get_contents palauttaa vain pari tyhjää rivinvaihtoa.
Edit2: Kun laitan käsin urlin (ei siis haeta tietokannasta), niin koodi toimii. Miten ihmeessä tuo merkistökoodaus voi kusta, kun tulostuksissa se näkyy oikein (paitsi phpmyadminissa)? Samaten toimii jos laitan käsin nimeksi L%C3%ADs (jonka ainakin chrome tarjoaa, kun copypastee osoitteen osoiteriviltä).
Miksi fopen-kikkailu, miksei yksinkertaisesti file_get_contents? (Toki molemmat toimivat.)
Minulla ainakin sivu latautuu oikein mutta XML-parseri jostain syystä parsii vain vähän alkupuolta. Looginen selitys olisi syntaksivirhe sivulla, ja siitähän selvitään siivoamalla data:
// Haku $url = "http://eu.wowarmory.com/character-sheet.xml?r=The+Maelstrom&cn=L%C3%ADs"; $str = file_get_contents($url); // strlen($str) == 103503 // Parsintayritys $parser = xml_parser_create(); xml_parse_into_struct($parser, $str, $vals, $index); xml_parser_free($parser); // strlen(json_encode($vals)) == 3669, aika vähän! // Siivous $str = tidy_repair_string($str, array("output-xhtml" => true)); // strlen($str) == 120870 // Parsinta uudelleen $parser = xml_parser_create(); xml_parse_into_struct($parser, $str, $vals, $index); xml_parser_free($parser); // strlen(json_encode($vals)) == 258027, parempi!
Kopioin suoraan tuon parserin, olisin kyllä itse käyttänyt file_get_contentsia.
Vika ei kuitenkaan ole siinä, sillä tuo nimi nyt tulee tietokannasta jostain syystä vääränlaisena. Kuten tuossa viime postauksessa mainitsin, niin jos syötän urlin käsin oikeanlaisella nimellä, niin tulee oikea sivu. Tietokannasta haettaessa kuitenkin näyttäisi merkistökoodaus kusevan, jota en millään ymmärrä, sillä kaikki on UTF-8:ia, sekä nimi myös tulostuu oikein muualle sivulle.
Siis missä kohdassa tarkalleen nimi on väärässä merkistössä? Et ole kovin selvä tämän suhteen. Mitä rawurlencode($name) palauttaa tuolla ParseSheet-funktiossa?
Ehkä olet määritellyt SQL-yhteydelle väärän merkistön. Kutsu mysql_set_charset("utf8")
(tai liian vanhalla PHP:n versiolla aja kysely SET NAMES 'utf8').
SQL-yhteyden merkistön määrittämisen jälkeen nimi näkyy phpmyadminissa oikein sekä tulostuu vieläkin oikein sivulle, mutta ei mene vieläkään läpi.
edit: rawurlencode($nimi): L%C3%ADs
toinen edit: no nyt sain rajattua ongelman tuohon ini_set funktioon. Jos kommentoin sen pois, niin taulukkoon tulee kyllä dataa, mutta HTML:ää. Armory ilmeisesti tunnistaa käyttäjän user-agentin perusteella ja lähettää joko HTML:ää tai XML:ää.
Nimi on aivan oikein. Mistä päättelit, että siinä olisi vikaa? Mihin kohtaan olet käsin syöttänyt osoitteen, jotta homma on toiminut? Oletko vertaillut, miten itse syöttämäsi osoite eroaa siitä, jonka koodisi tuottaa?
Koska phpmyadmin tulosti nimen aikaisemmin väärin (LÃs). Tuon takia yritin kokeilla pistää käsin tuonne ParseSheet-funktion sisälle suoraan $name = "Lís", jonka kanssa tiedot tuli ihan oikein. No nyt se näkyy oikein myös siellä phpmyadminissa, eli ei se ole missään vaiheessa ilmeisesti ollut merkistökoodauksessa vika, kun on kerran oikein tulostunut sivulle.
Eniveis, nyt tulee HTML:ää XML:n sijaan, joka pitäisi korjata.
Hommahan korjaantu yksinkertaisesti sillä, että laittoi realmin ja charrun nimeen urlencode().
Ja merkistöongelma korjaantui, kun laittoi MySQL-yhteyden merkistöksi tuon UTF-8:n.
Aihe on jo aika vanha, joten et voi enää vastata siihen.