PHP parser for OS X plist XML files
Category: Blog

Digging around today for a PHP parser for OSX plist files, I was surprised to find no good pre-existing solutions. Even Apple’s own site gives a relatively poor solution to the problem (see here). Normally SimpleXML is enough to handle most XML parsing needs, but the plist XML format is just broken enough to make parsing it with SimpleXML virtually impossible. Since I hadn’t played with XMLReader much, I thought it would be a good chance to give it a spin. For the anxious types, the code is available on github in my php_class_lib project, so dig right in. Read on for a simple example (included in the repos).

The original intent of the parser for me was to parse my iTunes’ library in PHP, so this example will show doing just that:

<?php

include("PlistParser.inc");

$parser = new plistParser();
$plist = $parser->parse(dirname(__FILE__) . "/iTunes.xml");
var_dump($plist);

And from that, the output is as follows:

array(8) {
  ["Major Version"]=>
  int(1)
  ["Minor Version"]=>
  int(1)
  ["Application Version"]=>
  string(5) "8.0.1"
  ["Features"]=>
  int(5)
  ["Show Content Ratings"]=>
  bool(true)
  ["Music Folder"]=>
  string(60) "file://localhost/Users/testUser/Music/iTunes/iTunes%20Music/"
  ["Library Persistent ID"]=>
  string(15) "C39203948AF3D3E"
  ["Tracks"]=>
  array(1) {
    [1]=>
    array(25) {
      ["Track ID"]=>
      int(1)
      ["Name"]=>
      string(8) "My Track"
      ["Artist"]=>
      string(9) "My Artist"
      ["Album"]=>
      string(8) "My Album"
      ["Genre"]=>
      string(8) "My Genre"
      ["Kind"]=>
      string(15) "MPEG audio file"
      ["Size"]=>
      int(123456)
      ["Total Time"]=>
      int(123456)
      ["Track Number"]=>
      int(1)
      ["Year"]=>
      int(2008)
      ["Date Modified"]=>
      string(20) "2008-03-03T03:33:33Z"
      ["Date Added"]=>
      string(20) "2008-03-03T03:33:33Z"
      ["Bit Rate"]=>
      int(128)
      ["Sample Rate"]=>
      int(44100)
      ["Comments"]=>
      string(20) "All Rights Reserved."
      ["Release Date"]=>
      string(20) "2007-03-12T04:01:37Z"
      ["Persistent ID"]=>
      string(14) "C3E339393939E3"
      ["Track Type"]=>
      string(4) "File"
      ["Podcast"]=>
      bool(false)
      ["Unplayed"]=>
      bool(true)
      ["File Type"]=>
      int(123456)
      ["File Creator"]=>
      int(123456)
      ["Location"]=>
      string(66) "file://localhost/Users/testUser/Music/iTunes/iTunes%20Music/my.mp3"
      ["File Folder Count"]=>
      int(4)
      ["Library Folder Count"]=>
      int(1)
    }
  }
}

As you can see, the PHP parser made short order of that task. From here you now have full access to all the metadata in your iTunes library. Feel free to use the class in your own projects and be sure to let me know what you build with it.

Tags: , , , , , , , , ,

20 Responses to “PHP parser for OS X plist XML files”

  1. BadKnees says:

    Great thanks, really needed this

  2. johnmph says:

    Hello, i tested your plist parser with the plist returned by itunes (for retrieve app information from app store) and this causes a problem because the plist has an empty array.

    When an empty array (and maybe an empty dict) is found, the parser tries to find a next element and didn’t see the end element of the array.

    That is the code that causes the problem (in parse_dict() and parse_array() methods) :

    $this->nextOfType(XMLReader::ELEMENT);
    do {

    } while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, “dict”));

    I replaced it by :

    $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT);
    while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, “dict”)) {

    }

    And that works fine now.

  3. For a generic solution to reading both XML PList files and Binary PList files check out:

    https://github.com/rodneyrehm/CFPropertyList

    Nice object oriented API to read in, traverse, access, modify and save PList files.

  4. Hi Jeremy,

    Great work!
    I’ve downloaded your classes to use our plist parser to work with Mac OS X user accounts obtained from the dscl command.

    I did this:

    $parser = new plistParser();
    $result = $parser->parseString(shell_exec(‘dscl -plist . readall /users’));

    and got this:

    Fatal error: Call to undefined method plistParser::readString() in
    lib/jsjohnst-php_class_lib-0371782/classes/parsers/plist/PlistParser.inc on line 125

    I’m no PHP expert but a quick look hints that the readString() command is nowhere to be found. Any hints?

    Erik

  5. I am surprised at how few people have tried to tackle this plist problem with PHP. I have been using CFPropertyList. It is ok but cannot handle writing back nested sets (yet anyway).

Leave a Comment

Spam Protection by WP-SpamFree