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