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