Update support for Amazon coverart grabbing (patch from Václav Nováček <waclaw66...
[patchfork.git] / player / metadata.php
CommitLineData
964dd0bc
JW
1<?php
2/*
3 Pitchfork Music Player Daemon Client
4 Copyright (C) 2007 Roger Bystrøm
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; version 2 of the License.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18*/
19 ob_start();
20
21 /* how much time must pass before we try searching for cover art again */
22 $COVER_SEARCH_AGAIN = 86400;
23
6f0e4e7c 24 include("aws_signed_request.php");
964dd0bc
JW
25 require_once("../inc/base.php");
26 require_once("metadata_cover.php");
27
6f0e4e7c
JW
28 function amazonlink($params)
29 {
30 $params["SubscriptionId"] = "15BH771NY941TX2NKC02";
31 $res = aws_signed_request("com", $params, "Access Key ID", "Secret Access Key");
32
33 return $res;
34 }
35
964dd0bc
JW
36 /* metadata should not require locking of session */
37 session_write_close();
38
39 $missing_metadata_dir = false;
40
41 if(!file_exists($metadata_dir)) {
42 if(!mkdir($metadata_dir, 0755)) {
43 $missing_metadata_dir = true;
44 }
45 }
46 if(!is_writeable($metadata_dir)) {
47 $missing_metadata_dir = true;
48 }
49
50 if($missing_metadata_dir) {
51 $xml = array_to_xml(array("result" => "nocachedir"));
52 echo $xml->asXML();
53 exit();
54 }
55
56 function escape_name($name) {
57 return str_replace(DIRECTORY_SEPARATOR, "_", $name);
58 }
59
60 function get_cover_base_name($artist, $album) {
61 global $cover_dir;
62 return $cover_dir . escape_name($artist) . " - " . escape_name($album);
63 }
64
65 function get_album_info_name($artist, $album) {
66 return get_cover_base_name($artist, $album) . ".txt";
67 }
68 function get_lyric_filename($artist, $title) {
69 global $cover_dir;
70 return $cover_dir . escape_name($artist) . " - ". escape_name($title) . ".lyric";
71 }
72
73 function find_lyrics($arr) {
74 foreach($arr as $val) {
75 if(!is_array($val))
76 continue;
77 if(isset($val['name'])&&$val['name']=="RETURN") {
78 return $val['children'];
79 }
80 else if(is_array($val)) {
81 $ret = find_lyrics($val);
82 if($ret)
83 return $ret;
84 }
85 }
86 return false;
87 }
88
89 function fp_get_contents($fp) {
90 $ret = "";
91 $tmp = false;
92 while($tmp = fgets($fp))
93 $ret .= $tmp;
94 fseek($fp, 0);
95 if(strlen($ret)==0)
96 return false;
97 return $ret;
98 }
99
100 /* Queries amazon with the specified url, strict serach first and then a more careless one,
101 * will urlencode artist and albumname
102 * returns xml document or false upon failure */
6f0e4e7c 103 function amazon_album_query($params) {
964dd0bc
JW
104 $stype = array("Title", "Keywords");
105 $artist = urlencode($artist);
106 $album = urlencode($album);
107 foreach($stype as $st) {
108 if(!amazon_wait())
109 return false;
6f0e4e7c 110 $xml = amazonlink($params);
964dd0bc
JW
111 if($xml&&isset($xml->Items[0])&&isset($xml->Items[0]->Item[0]))
112 return $xml;
113 }
114 return false;
115 }
116
117 /* returns file pointer or false */
118 function get_album_lock($artist, $album) {
119 $file_name = get_album_info_name($artist, $album);
120 $exists = file_exists($file_name);
121 $fp = false;
122
123 if($exists)
124 $fp = @fopen($file_name, "r+");
125 else $fp = @fopen($file_name, "w+");
126 if($fp && flock($fp, LOCK_EX))
127 return $fp;
128
129 trigger_error("Can't lock album-file: $file_name", E_USER_WARNING);
130 return false;
131 }
132
133 /* waits for appropriate amazon time, have to be called before making any amazon requests
134 returns true if ok to continue otherwise false */
135 function amazon_wait() {
136 global $metadata_dir;
137
138 /* rationale behind this:
139 * amazon requires that we don't make more than one request pr. second pr. ip */
140
141 $file_name = $metadata_dir . "amazon_time";
142 if(file_exists($file_name))
143 $fp = @fopen($file_name, "r+");
144 else $fp = @fopen($file_name, "w+");
145
146 if(!$fp) {
147 trigger_error("Can't open amazon_time", E_USER_WARNING);
148 return false;
149 }
150 if(!flock($fp, LOCK_EX)) {
151 @fclose($fp);
152 trigger_error("Can't lock amazon_time", E_USER_WARNING);
153 return false;
154 }
155
156 $last = fp_get_contents($fp);
157 if($last) {
158 $stime = 1000;
159 if(is_numeric($last)) {
160 $stime = current_time_millis() - $last;
161 }
162 $stime = abs($stime);
163 if($stime<1000)
164 usleep($stime*1000); // micro seconds
165 }
166
167 if(@fwrite($fp, current_time_millis())===false) {
168 @fclose($fp);
169 trigger_error("Can't write to amazon_time", E_USER_WARNING);
170 return false;
171 }
172 else {
173 @fclose($fp);
174 return true;
175 }
176 }
177
178 /* returns artist and album info and get's album lock or dies */
179 /* return value: array($fp, $artist, $album) */
180 function init_album_artist_or_die() {
181 ob_end_clean();
182 header("Content-Type: text/xml; charset=UTF-8");
183
184 $album = "";
185 $artist = "";
186 if(isset($_GET['artist'])&&isset($_GET['album']) &&
187 strlen(trim($_GET['artist']))>0&&strlen(trim($_GET['album']))>0) {
188 $album = trim($_GET['album']);
189 $artist = trim($_GET['artist']);
190 }
191 else {
192 $xml = array_to_xml(array("result" => "missingparam"));
193 echo $xml->asXML();
194 exit();
195 }
196
197 $fp = get_album_lock($artist, $album);
198
199 if(!$fp) {
200 $xml = array_to_xml(array("result" => "failed"));
201 echo $xml->asXML();
202 exit();
203 }
204 return array($fp, $artist, $album);
205 }
206
207 /* returns array(artist, album, filename) or false */
208 function get_current_info() {
209 try {
210 $pl = get_playback();
211 if($pl) {
212 $info = $pl->getCurrentSong();
213 if(isset($info['Artist'])&&isset($info['Title'])) {
214 $artist = trim($info['Artist']);
215 $title = trim($info['Title']);
216 $file_name = $info['file'];
217 return array($artist, $title, $file_name);
218 }
219 }
220 $pl->disconnect();
221 }
222 catch(PEARException $e) {
223 }
224 return false;
225 }
226
227
228 function get_cover() {
6f0e4e7c 229 global $COVER_SEARCH_AGAIN, $cover_providers;
964dd0bc
JW
230
231 list($fp, $artist, $album) = init_album_artist_or_die();
232
233 $xml = fp_get_contents($fp);
234 if($xml) {
235 $xml = @simplexml_load_string($xml);
236 if($xml) {
237 $use_cache = true;
238 if(isset($xml->notfound)&&is_numeric((string)$xml->notfound[0])) {
239 $time = @intval((string)$xml->notfound[0]);
240 if($time+$COVER_SEARCH_AGAIN<time())
241 $use_cache = false;
242 }
243 else if(!isset($xml->image[0])&&!isset($xml->thumbnail[0])) {
244 $use_cache = false;
245 }
246
247 if($use_cache) {
248 $xml->addChild("cached", "true");
249 echo $xml->asXML();
250 exit();
251 }
252 }
253 }
254
255
256 $res = false;
257
258 foreach($cover_providers as $cp) {
259 $res = $cp($artist, $album);
260 if($res&&is_array($res))
261 break;
262 }
263
264 if($xml) {
265 if($res&&is_array($res)) {
266 foreach($res as $key => $val) {
267 if(!isset($xml->$key))
268 $xml->$key = (string)$val;
269 }
270 }
271 else {
272 $xml->notfound = time();
273 }
274 }
275 else {
276 if($res&&is_array($res)) {
277 $res['time'] = time();
278 $xml = array_to_xml($res);
279 }
280 else {
281 $xml = array("notfound" => time());
282 $xml = array_to_xml($xml);
283 }
284 }
285
286 @fwrite($fp, $xml->asXML());
287
288 @fclose($fp);
289 echo $xml->asXML();
290 exit();
291 }
292
293 function get_review() {
6f0e4e7c 294 global $COVER_SEARCH_AGAIN;
964dd0bc
JW
295
296 list($fp, $artist, $album) = init_album_artist_or_die();
297
298 $xml = fp_get_contents($fp);
299 $asin = "";
300 $desc = false;
301 $review = false;
302 $review_src = false;
303 $no_search = false;
304 $failed = false;
305 $changed = false;
306
307
308 if($xml) {
309 $xml = @simplexml_load_string($xml);
310 if($xml) {
311 if(isset($xml->rnotfound)&&is_numeric((string)$xml->rnotfound[0])) {
312 $time = @intval((string)$xml->rnotfound[0]);
313 if($time+$COVER_SEARCH_AGAIN>time())
314 $no_search = true;
315 }
316 }
317 }
318
319 if(!$xml||(!(isset($xml->review[0])||isset($xml->desc[0]))&&!$no_search)) {
320 $res = false;
321 if(!amazon_wait()) {
322 echo array_to_xml(array("result" => "failed"))->asXML();
323 exit();
324 }
325
326 if($xml&&isset($xml->asin[0])) {
6f0e4e7c 327 $res = amazonlink(array("Operation"=>"ItemLookup", "IdType"=>"ASIN", "ItemId"=>"urlencode($xml->asin[0])"));
964dd0bc
JW
328 $asin = false;
329 }
330 else {
6f0e4e7c 331 $res = @amazon_album_query(array("Operation"=>"ItemSearch", "SearchIndex"=>"Music", "Artist"=>"$artist", "Album"=>"$album"));
964dd0bc
JW
332 }
333 if($res) {
334 if($res&&isset($res->Items[0])&&isset($res->Items[0]->Item[0])) {
335 $p = $res->Items[0]->Item[0];
336 $asin = (string) $p->ASIN;
337 if(isset($p->EditorialReviews[0])) {
338 $p = $p->EditorialReviews[0];
339 foreach($p->EditorialReview as $er) {
340 if(!$desc&&"Album Description" == (string)$er->Source) {
341 $desc = (string) $er->Content;
342 }
343 else if(!$review) {
344 $review_src = (string) $er->Source;
345 $review = (string) $er->Content;
346 }
347 }
348 }
349 /* set info in xml-file... */
350 if($xml) {
351 if($review) {
352 $xml->review_src = htmlspecialchars($review_src);
353 $xml->review = htmlspecialchars($review);
354 }
355 if($desc) {
356 $xml->desc = htmlspecialchars($desc);
357 }
358 if(!isset($xml->asin[0])) {
359 $xml->addChild("asin", $asin);
360 $changed = true;
361 }
362 if(!$review&&!$desc) {
363 $failed = true;
364 }
365 else {
366 $changed = true;
367 }
368 }
369 else {
370 $xml = array();
371 $xml['asin'] = $asin;
372 if($desc)
373 $xml['desc'] = $desc;
374 if($review) {
375 $xml['review_src'] = $review_src;
376 $xml['review'] = $review;
377 }
378 if(!$review&&!$desc)
379 $failed = true;
380 $xml = array_to_xml($xml);
381 $changed = true;
382 }
383 }
384 else {
385 $failed = true;
386 }
387 }
388 else {
389 $failed = true;
390 }
391 }
392 else {
393 $xml->addChild("cached", "true");
394 }
395
396 if($xml) {
397 if($failed) {
398 if(isset($xml->rnotfound)) {
399 $xml->rnotfound = time();
400 }
401 else {
402 $xml->addChild("rnotfound", time());
403 }
404 @fwrite($fp, $xml->asXML());
405 }
406 else if($changed) {
407 @fwrite($fp, $xml->asXML());
408 }
409 }
410 else {
411 $xml = array_to_xml(array("rnotfound" => time()));
412 @fwrite($fp, $xml->asXML());
413 }
414 @fclose($fp);
415 echo $xml->asXML();
416 exit();
417 }
418
419 /* artist, title and song file name in system */
420 function _get_lyric_lyricwiki($artist, $title, $file_name) {
421 $file = get_lyric_filename($artist, $title);
422 $fp = fsockopen("lyricwiki.org", 80);
423 if(!$fp) {
424 $xml = array_to_xml(array("result"=>"connectionfailed"));
425 return $xml->asXML();
426 }
427
428 $out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
429 $out .= "<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" ";
430 $out .= "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" ";
431 $out .= "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ";
432 $out .= "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ";
433 $out .= "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" ";
434 $out .= "xmlns:tns=\"urn:LyricWiki\">";
435 $out .= "<SOAP-ENV:Body><tns:getSong xmlns:tns=\"urn:LyricWiki\">";
436 $out .= "<artist xsi:type=\"xsd:string\">";
437 $out .= htmlspecialchars($artist);
438 $out .= "</artist>";
439 $out .= "<song xsi:type=\"xsd:string\">";
440 $out .= htmlspecialchars($title);
441 $out .= "</song>";
442 $out .= "</tns:getSong></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n";
443
444 $head = "POST /server.php HTTP/1.1\r\n";
445 $head .= "Host: lyricwiki.org\r\n";
446 $head .= "SOAPAction: urn:LyricWiki#getSong\r\n";
447 $head .= "Content-Type: text/xml; charset=UTF-8\r\n";
448 $head .= "User-Agent: RemissPitchfork/0.1\r\n";
449 $head .= "Content-Length: " . str_byte_count($out) . "\r\n";
450 $head .= "Connection: Close\r\n\r\n";
451
452 fwrite($fp, $head . $out);
453
454 $responseHeader = "";
455 /* assume everything is dandy */
456 do {
457 $responseHeader.= fread($fp, 1);
458 }
459 while (!preg_match('/\\r\\n\\r\\n$/', $responseHeader));
460
461 $ret = "";
462 while(!feof($fp)) {
463 $ret .= fgets($fp, 128);
464 }
465 fclose($fp);
466 /* stupid hack to get around wrong xml declearation */
467 $qmark = "?";
468 if(strpos($ret, "<". $qmark . "xml version=\"1.0\" encoding=\"ISO-8859-1\"".$qmark.">")===0)
469 $ret = str_replace("<". $qmark . "xml version=\"1.0\" encoding=\"ISO-8859-1\"".$qmark.">",
470 "<". $qmark . "xml version=\"1.0\" encoding=\"UTF-8\"".$qmark.">",
471 $ret);
472
473 /*echo $ret;
474 exit();*/
475 $parser = new xml2array();
476 $parser->parse($ret);
477 $data = find_lyrics($parser->arrOutput);
478 // check that data is ok and lyrics exist
479 if($data&&isset($data[2]['tagData'])) {
480 $res = array();
481 foreach($data as $d) {
482 if($d['name']=="ARTIST")
483 $res['artist'] = $d['tagData'];
484 else if($d['name']=="SONG")
485 $res['title'] = $d['tagData'];
486 else if($d['name']=="LYRICS")
487 $res['lyric'] = $d['tagData'];
488 else if($d['name']=="URL")
489 $res['url'] = $d['tagData'];
490 }
491 $res['from'] = "lyricwiki.org";
492 $res['time'] = time();
493 /* this caching thing will have to be extracted if we
494 * put in another lyrics source */
495 if(trim($res['lyric'])&&trim($res['lyric'])!="Not found") {
496 $xml = array_to_xml(array("result" => $res));
497 $xml->addChild("file", htmlspecialchars($file_name));
498 $res = $xml->asXML();
499 @file_put_contents($file, $res);
500 }
501 else {
502 $out = array("result" => "notfound");
503 if(isset($res['url']))
504 $out['url'] = $res['url'];
505 $res = array_to_xml($out);
506 $res = $res->asXML();
507 }
508 return $res;
509 }
510 return false;
511 }
512
513 /* $file: filename of cached version
514 * $file_name: file name of song */
515 function _get_lyric_cache($file, $file_name) {
516 $xml = @simplexml_load_file($file);
517 if($xml) {
518 $add_file = true;
519 if(isset($xml->file)) {
520 foreach($xml->file as $f) {
521 if(((string)$f)==$file_name)
522 $add_file = false;
523 }
524 }
525 if($add_file) {
526 $xml->addChild("file", htmlspecialchars($file_name));
527 @file_put_contents($file, $xml->asXML());
528 }
529 $xml->addChild("cached", "true");
530 return $xml->asXML();
531 }
532 return false;
533 }
534
535 function get_lyric($info = null) {
536 header("Content-Type: text/xml; charset=UTF-8");
537 ob_end_clean();
538 if(is_null($info))
539 $info = get_current_info();
540 if(!$info) {
541 $xml = array_to_xml(array("result"=>"failed"));
542 echo $xml->asXML();
543 exit();
544 }
545 $artist = $info[0];
546 $title = $info[1];
547 $file_name = $info[2];
548
549 $file = get_lyric_filename($artist, $title);
550 if(file_exists($file)&&!isset($_GET['force'])) {
551 $xml = _get_lyric_cache($file, $file_name);
552 if($xml) {
553 echo $xml;
554 exit();
555 }
556 }
557
558 $xml = _get_lyric_lyricwiki($artist, $title, $file_name);
559 if($xml) {
560 echo $xml;
561 }
562 else {
563 echo array_to_xml(array("result" => "failed"))->asXML();
564 }
565 exit();
566 }
567
568 function get_pic() {
569
570 global $cover_dir;
571 $b_name = basename(trim($_GET['pic']));
572 $name = $cover_dir . $b_name;
573 if(file_exists($name)&&is_readable($name)) {
574 if(function_exists("finfo_open")&&function_exists("finfo_file")) {
575 $f = finfo_open(FILEINFO_MIME);
576 header("Content-Type: " . finfo_file($f, $name));
577 }
578 else if(function_exists("mime_content_type")) {
579 header("Content-Type: " . mime_content_type($name));
580 }
581 else {
582 header("Content-Type: image/jpeg");
583 }
584 $c = "Content-Disposition: inline; filename=\"";
585 $c .= rawurlencode($b_name) . "\"";
586 header($c);
587 echo @file_get_contents($name);
588 ob_end_flush();
589 exit();
590 }
591 else {
592 echo "File does not exist\n";
593 trigger_error("Did not find albumart althought it was requested", E_USER_WARNING);
594 exit();
595 }
596 }
597
598 function get_recommendations_from_playlist() {
599 require_once("../player/openstrands.php");
600 $pl = get_playlist();
601 $list = $pl->getPlaylistInfo();
602 $artist = array();
603 foreach($list as $song) {
604 if(isset($song['Artist'])&&$song['Artist'])
605 $artist[$song['Artist']] = true;
606 }
607 $artist = array_keys(array_change_key_case($artist));
608 $pl->disconnect();
609
610 header("Content-Type: text/xml; charset=UTF-8");
611
612 $ret = strands_get_recommendations($artist);
613 $res = array();
614 if(!$ret || ! count($ret)) {
615 $res['result'] = is_array($ret)?"notfound":"failed";
616 echo array_to_xml($res)->asXML();
617 exit();
618 }
619 $db = get_database();
620 foreach($ret as $a) {
621 $tmp = array();
622 $tmp['name'] = $a;
623 $tmp['album'] = $db->getMetadata("Album", "Artist", $a);
624 $res[] = $tmp;
625 }
626 $out = array("result" => $res);
627 $db->disconnect();
628 echo array_to_xml($out)->asXML();
629 }
630
631 function do_houseclean() {
632 /* this is a *very* inefficient method, but it's needed... */
633 //header("Content-Type: text/xml; charset=UTF-8");
634 header("Content-type: multipart/x-mixed-replace;boundary=--ThisRandomString");
635
636 global $metadata_dir;
637
638 echo "--ThisRandomString\n";
639 $out = "Content-type: text/html\n\n".
640 "<html><head><title>Housecleaning</title></head><body>\n".
641 "<p>Performing housecleaning, please wait...</p>\n";
642
643 echo "$out--ThisRandomString\n";
644 ob_end_flush();
645 flush();
646 set_time_limit(300); // this might take a while, but
647 // shouldn't be more than 5 mins even on slow machines
648 $db = get_database();
649 $res = "failed";
650 try {
651 $time = current_time_millis();
652 $list = $db->getAll();
653 if(!isset($list['file']))
654 return;
655 $files = $list['file'];
656 $db->disconnect();
657 $list = scandir($metadata_dir);
658 $total = count($list);
659 $fixed = 0;
660 $errors = 0;
661 $fcount = 0;
662 $fcount_inv = 0;
663 $tcount = 0;
664 foreach($list as $f) {
665 $r = strrpos($f, ".lyric");
666 $tcount++;
667 if($r!==false&&$r+6==strlen($f)) {
668 $xml = @simplexml_load_file($metadata_dir . $f);
669 $fcount++;
670 if($fcount%100 == 0) {
671 echo $out;
672 echo "<p>Processed $fcount (".(int)($tcount*100/$total)."%)..</p>\n";
673 echo "--ThisRandomString\n";
674 flush();
675
676 }
677 if($xml) {
678 $x_files = array();
679 foreach($xml->file as $v) {
680 $x_files[] = (string)$v;
681 }
682 $dis = array_intersect($x_files, $files);
683 if(count($dis)!=count($x_files)) {
684 $dom = @dom_import_simplexml($xml);
685 if($dom===false) {
686 $errors++;
687 continue;
688 }
689
690 while($elem = $dom->getElementsByTagName("file")->item(0)) {
691 $dom->removeChild($elem);
692 }
693
694 $xml = simplexml_import_dom($dom);
695 array_to_xml($dis, $xml, "file");
696 @$xml->asXML($metadata_dir . $f);
697 $fixed++;
698 }
699 }
700 else {
701 $fcount_inv++;
702 }
703 }
704 }
705 $result = array("time" => intval(current_time_millis() - $time), "fixed" => $fixed, "errors" => $errors);
706 }
707 catch(PEAR_Exception $e) {
708 }
709 echo "Content-type: text/html\n\n";
710 echo "<p>";
711 if(is_array($result)) {
712 echo "Result of cleaning:<br/>\n";
713 echo "$fcount files checked in " . $result['time'] . "ms of which $fcount_inv was invalid<br/>";
714 echo "Fixed: " . $result['fixed'] . "<br/>";
715 echo "Errors: " . $result['errors'] . "<br/>\n";
716
717 }
718 else if($result=="failed") {
719 echo "It appears housecleaning failed, check your MPD settings";
720 }
721 else {
722 echo "hmm.. somethings wrong, try again";
723 }
724 echo "</p><p><a href='config.php'>Back to configuration</a></p></body></html>\n";
725 echo "\n--ThisRandomString\n";
726 }
727
728
729 if(!isset($iamincluded)) {
730 if(isset($_GET['cover'])) get_cover();
731 else if(isset($_GET['review'])) get_review();
732 else if(isset($_GET['lyric'])) get_lyric();
733 else if(isset($_GET['pic'])) get_pic();
734 else if(isset($_GET['housecleaning'])) do_houseclean();
735 else if(isset($_GET['plrecommend'])) get_recommendations_from_playlist();
736 else {
737 header("Content-Type: text/xml; charset=UTF-8");
738 $xml = array_to_xml(array("result"=>"what do you want?"));
739 echo $xml->asXML();
740 exit();
741 }
742 }
743
744
745class xml2Array {
746
747 var $arrOutput = array();
748 var $resParser;
749 var $strXmlData;
750
751 /* parse to utf-8 */
752 function parse($strInputXML) {
753
754 $this->resParser = xml_parser_create("UTF-8");
755
756 xml_set_object($this->resParser,$this);
757 xml_set_element_handler($this->resParser, "tagOpen", "tagClosed");
758 xml_parser_set_option($this->resParser, XML_OPTION_TARGET_ENCODING, "UTF-8");
759
760 xml_set_character_data_handler($this->resParser, "tagData");
761
762 $this->strXmlData = xml_parse($this->resParser,$strInputXML );
763 if(!$this->strXmlData) {
764 die(sprintf("XML error: %s at line %d",
765 xml_error_string(xml_get_error_code($this->resParser)),
766 xml_get_current_line_number($this->resParser)));
767 }
768
769 xml_parser_free($this->resParser);
770
771 return $this->arrOutput;
772 }
773 function tagOpen($parser, $name, $attrs) {
774 $tag=array("name"=>$name,"attrs"=>$attrs);
775 array_push($this->arrOutput,$tag);
776 }
777
778 function tagData($parser, $tagData) {
779 if(isset($this->arrOutput[count($this->arrOutput)-1]['tagData']))
780 $this->arrOutput[count($this->arrOutput)-1]['tagData'] .= $tagData;
781 else
782 $this->arrOutput[count($this->arrOutput)-1]['tagData'] = $tagData;
783 }
784
785 function tagClosed($parser, $name) {
786 $this->arrOutput[count($this->arrOutput)-2]['children'][] = $this->arrOutput[count($this->arrOutput)-1];
787 array_pop($this->arrOutput);
788 }
789}
790
791?>
This page took 0.08492 seconds and 4 git commands to generate.