Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Ongelma erikoismerkkien kanssa

Sivun loppuun

punppis [25.11.2010 20:30:19]

#

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".

Merri [25.11.2010 20:47:43]

#

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.

punppis [25.11.2010 20:50:32]

#

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.

Merri [25.11.2010 21:04:24]

#

Mitä $xml-muuttuja sisältää ennen syöttöä xmlToArray-funktioon? Tuleeko virhesivu vai oikea sivu?

punppis [25.11.2010 21:06:51]

#

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ä).

Metabolix [25.11.2010 21:22:11]

#

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!

punppis [25.11.2010 21:30:46]

#

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.

Metabolix [25.11.2010 21:50:05]

#

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').

punppis [25.11.2010 21:54:54]

#

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:ää.

Metabolix [25.11.2010 22:00:16]

#

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?

punppis [25.11.2010 22:04:07]

#

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().

punppis [26.11.2010 02:50:01]

#

Ja merkistöongelma korjaantui, kun laittoi MySQL-yhteyden merkistöksi tuon UTF-8:n.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta