Version: 1.0
Type: Class
Category: Other
License: GNU General Public License
Description: A small and quick class to get CDDB information using the Linux program cd-discid.
<?php ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### ################### ################### ################### Aces XMMS-PHP MP3 Jukebox v0.1.0 ################### ################### -------------------------------- ################### ################### ################### ################### Based on XMMS-Control by Joe Thielen ################### ################### ################### ################### Designed by Ace ([email protected]) ################### ################### ################### ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### ### You may use or modify this program for any non-profit use ### ### as long as there is a the copyright notice displayed in a ### ### comment inside the output html ### ### (i.e. <!-- Generated by XMMS-PHP. ### ### http://bassetts.port5.com (C) Ace 2003 -->) ### ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### ### ### ### PHPlibcddb 0.01 - PHP-based implementation of the CDDB protocol ### ### Copyright (C) 2003 David Jonathan Grant ### ### ### ### This program is free software; you can redistribute it and/or ### ### modify it under the terms of the GNU General Public License ### ### as published by the Free Software Foundation; either version 2 ### ### of the License, or (at your option) any later version. ### ### ### ### This program is distributed in the hope that it will be useful, ### ### but WITHOUT ANY WARRANTY; without even the implied warranty of ### ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ### ### GNU General Public License for more details. ### ### ### ### You should have received a copy of the GNU General Public License ### ### along with this program; if not, write to the Free Software ### ### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ### ### ### ### David Jonathan Grant <[email protected]> ### ### ### ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### ############### ############### ############### CDDB Connectivity Class ############### ############### ############### ############### Designed by: Ace. ############### ############### <[email protected]> ############### ############### ############### ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### #### #### #### Usage Example: #### #### -------------- #### #### #### #### echo "<PRE>"; #### #### #### #### include("classes/class.cddb.php"); #### #### #### #### $cddb = new cddb(); #### #### $cddb->connect(); #### #### $cddb->protocol(5); #### #### #### #### print_r($cddb->genres()); #### #### print_r($cddb->help("discid")); #### #### print_r($cddb->log()); #### #### print_r($cddb->status()); #### #### $info = $cddb->import(); #### #### $data = $cddb->query($info['discid'], $info['tracks'], #### #### $info['timing'], $info['length']); #### #### print_r($data[0]); #### #### print_r($cddb->read($data[0]['category'], $info['discid'])); #### #### print_r($cddb->motd()); #### #### print_r($cddb->version()); #### #### $cddb->disconnect(); #### #### print_r($cddb->messages); #### #### #### #### echo "</PRE>"; #### #### #### ##################################################################################### ##################################################################################### class cddb { var $connection = NULL; var $messages = NULL; function code($response) { return (substr($response, 0, 3)); } function connect($servernumber = 0) { $serverport = 8880; $server[0] = "freedb.freedb.org"; // Random freedb server $server[1] = "freedb.freedb.de"; // Dortmund, Germany $server[2] = "at.freedb.org"; // Vienna, Austria $server[3] = "au.freedb.org"; // Sydney, Australia $server[4] = "bg.freedb.org"; // Sofia, Bulgaria $server[5] = "ca.freedb.org"; // Winnipeg, MB Canada $server[6] = "de.freedb.org"; // Berlin, Germany $server[7] = "es.freedb.org"; // Madrid, Spain $server[8] = "lu.freedb.org"; // Betzdorf, Luxemburg $server[9] = "uk.freedb.org"; // London, UK $server[10] = "us.freedb.org"; // San Jose, CA USA if (!isset($this->serverport)) { $this->serverport = 8880; } if (!isset($servernumber)) { $servernumber = 0; } // Connect to the central FreeDB server. $this->connection = fsockopen($this->server[$this->servernumber], $this->serverport); // Checck to see if the socket connected properly. if (is_resource($this->connection) == FALSE) { return (FALSE); } else { //$code = $this->code($this->parse(1)); switch ($code = $this->code($this->parse(1))) { case 200: $this->messages[] = "200: OK, Read/Write Allowed."; return ($this->hello()); break; case 201: $this->messages[] = "200: OK, Read Only."; return ($this->hello()); break; case 432: $this->messages[] = "432: No Connections Allowed: Permission Denied."; return (FALSE); case 433: $this->messages[] = "433: No Connections Allowed: X Users Allowed, Y Currently Active."; return (FALSE); case 434: $this->messages[] = "434: No Connections Allowed: System Load Too High."; return (FALSE); default: return ($this->errors($code)); } } } function discid($tracks, $offsets, $time) { $this->send("discid " . $tracks . " " . implode(" ", $offsets) . " " . $time); $header = $this->parse(1); switch ($code = $this->code($header)) { case 200: $this->messages[] = "200: Calculated Disc ID Properly."; preg_match("/.+ (S+)^$/", $header, $matches); return ($matches[1]); default: return ($this->errors($code)); } } function disconnect() { // Disconnect from server. $this->send("quit"); switch ($code = $this->code($this->parse(1))) { case 230: $this->messages[] = "230: OK, Goodbye."; fclose($this->connection); return (TRUE); default: return ($this->errors($code)); } } function errors($code) { // Handle general error status codes from other functions. switch ($code) { case 402: $this->messages[] = "402: Server Error."; return (FALSE); case 408: $this->messages[] = "408: CGI Environment Error."; return (FALSE); case 500: $this->messages[] = "500: Command Syntax Error."; return (FALSE); case 530: $this->messages[] = "503: Server Error, Server Timeout."; return (FALSE); default: $this->messages[] = "Received Unrecognised Code (" . $code . ")"; return (FALSE); } } function genres() { // Return a list of muscial genres. $this->send("cddb lscat");; switch ($code = $this->code($this->parse(1))) { case 210: $this->messages[] = "210: OK, Category List Follows."; return ($this->parse(0)); default: return ($this->errors($code)); } } function hello() { // Handshake $sys = posix_uname(); $usr = posix_getpwuid(posix_geteuid()); // Send 'hello' command to the conneccted server. $this->send("cddb hello " . $usr['name'] . " " . $sys['nodename'] . " PHPlibcddb 0.01"); switch ($code = $this->code($this->parse(1))) { case 200: $this->messages[] = "200: OK, Handshake Successful."; // Handshake was completed successfully. return (TRUE); case 402: // Not *really* a problem, but it is important to know if this is occurring frequently. $this->messages[] = "402: Already Shook Hands."; return (TRUE); case 431: // $this->messages[] = "431: Handshake Not Successful. Closing Connection."; return (FALSE); default: return ($this->errors($code)); } } function help($topic) { // Request help from server $this->send("help " . $topic); switch ($code = $this->code($this->parse(1))) { case 210: $this->messages[] = "210: OK, Help Information Follows."; return ($this->parse(0)); case 401: $this->messages[] = "401: No Help Information Available."; return (FALSE); default: return ($this->errors($code)); } } function import() { // Grab the CD information from the local machine. // This will only work on Unix-based machines with cd-discid. $data = explode(" ", `cd-discid /dev/cdrom`); $info['discid'] = array_shift($data); $info['tracks'] = array_shift($data); $info['length'] = array_pop($data); $info['timing'] = $data; return ($info); } function log() { // Request usagee log from the server. $this->send("log"); switch ($code = $this->code($this->parse(1))) { case 210: $this->messages[] = "210: OK, Log Summary Follows."; return ($this->parse(0)); case 211: $this->messages[] = "211: OK Log Follows."; return ($this->parse(0)); case 401: $this->messages[] = "401: Permission Denied."; return (FALSE); case 402: $this->messages[] = "402: No Log Information Available."; return (FALSE); case 501: $this->messages[] = "501: Invalid Start/End Date."; return (FALSE); default: return ($this->errors($code)); } } function motd() { // Request the Message of the Day $this->send("motd"); switch ($code = $this->code($this->parse(1))) { case 210: $this->messages[] = "210: Last Modified MM/DD/YYYY HH:MM:SS. MOTD Follows."; return ($this->parse(0)); case 401: $this->messages[] = "401: No Message of the Day Available."; return (FALSE); default: return ($this->errors($code)); } } function parse($lines) { // Check if read is for multiple (0) or single (1) lines. if ($lines == 1) { $response = ""; // Loop through the response while (feof($this->connection) == FALSE) { // Read a character from the response. $character = fgetc($this->connection); // Continue until we get a carriage return. if ($character == chr(13)) { break; } // Add current character to response string. if (empty($response)) { $response = $character; } else { $response = $response . $character; } } return (trim($response)); } else { $offset = 0; $response = array(); while (feof($this->connection) == FALSE) { // Prevent PHP throwing an error. if (array_key_exists($offset, $response) == FALSE) { // Populate current array offset $response[$offset] = ""; // Remove the NL character from the response. fgetc($this->connection); } // Read a character from the response. $character = fgetc($this->connection); // Check for an ASCII CR character. if ($character == chr(13)) { // Add a new line to the array $response[$offset] = trim($response[$offset]); $offset++; continue; } // If the character is a fullstop (.) and is at the beginning of the line, delete the row, and exit. // Reasoning: a fullstop (.) is the terminating character for multiple line responses. if ($character == chr(46) && strlen($response[$offset]) == 0) { unset($response[$offset]); // Grab what *SHOULD* be the last character (CR) from the response. fgetc($this->connection); break; } else { // Add the character to the current row in the reponse array. if (empty($response[$offset])) { $response[$offset] = $character; } else { $response[$offset] = $response[$offset] . $character; } } } return ($response); } } function protocol($protocol) { // Change the current CDCDP level. $this->send("proto " . $protocol); switch ($code = $this->code($this->parse(1))) { case 200: $this->messages[] = "200: CDDB Protocol Level, Current Level, Current Supported Level."; return (TRUE); case 201: $this->messages[] = "201: OK, Protocol Level Now Current Level."; return (TRUE); case 501: $this->messages[] = "501: Illegal Protocol Level."; return (FALSE); case 502: $this->messages[] = "502: Protocol Level Already Current Level."; return (FALSE); default: return ($this->errors($code)); } } function query($discid, $tracks, $offset, $length) { // Find matches for CD data. $this->send("cddb query " . $discid . " " . $tracks . " " . implode(" ", $offset) . " " . $length); $header = $this->parse(1); switch($code = $this->code($header)) { case 200: $this->messages[] = "200: Found Exact Match."; preg_match("/^d{3} (S+) (S+) (.+/.+)$/", $header, $matches); $results[0]['category'] = $matches[1]; $results[0]['discid'] = $matches[2]; $results[0]['dtitle'] = $matches[3]; return ($results); case 202: $this->messages[] = "202: No Match Found."; return (FALSE); case 210: $this->messages[] = "210: Found Exact Matches. List Follows."; foreach ($this->parse(0) as $offset => $data) { // Extract CD information from response. preg_match("/^(S+) (S+) (.+/.+)$/", $data, $matches); $results[$offset]['category'] = $matches[1]; $results[$offset]['discid'] = $matches[2]; $results[$offset]['dtitle'] = $matches[3]; } return ($results); case 211: $this->messages[] = "211: Found Inexact Matches. List Follows."; foreach ($this->parse(0) as $offset => $data) { // Extract CD information from response. preg_match("/^(S+) (S+) (.+/.+)$/", $data, $matches); $results[$offset]['category'] = $matches[1]; $results[$offset]['discid'] = $matches[2]; $results[$offset]['dtitle'] = $matches[3]; } return ($results); case 403: $this->messages[] = "403: Database Entry is Corrupt."; return (FALSE); case 409: $this->messages[] = "409: No Handshake."; return (FALSE); default: return ($this->errors($code)); } } function read($category, $discid) { // Fetch the track data corresponding to the passed CD data. $this->send("cddb read " . $category . " " . $discid); switch ($code = $this->code($this->parse(1))) { case 210: $this->messages[] = "200: OK, CDDB Database Entry Follows."; return ($this->parse(0)); case 401: $this->messages[] = "401: Specified CDDB Entry Not Found."; return (FALSE); case 402: $this->messages[] = "402: Server Error."; return (FALSE); case 403: $this->messages[] = "403: Database Entry is Corrupt."; return (FALSE); case 409: $this->messages[] = "409: No Handshake."; return (FALSE); default: return ($this->errors($code)); } } function send($request) { // Wrapper for sending request. fputs($this->connection, $request . "n"); } function sites() { // List all the alternative servers. $this->send("sites"); // Check the status code. switch ($code = $this->code($this->parse(1))) { case 210: $this->messages[] = "210: OK, Site Information Follows."; // Read in all sites. $sites = $this->parse(0); // Loop through server list and extract different parts. foreach ($sites as $offset => $data) { preg_match("/^(.+) (.+) (d+) (.+) ([N|S]d{3}.d{2}) ([E|W]d{3}.d{2}) (.+)/", $data, $matches); $servers[$offset]['hostname'] = $matches[1]; $servers[$offset]['protocol'] = $matches[2]; $servers[$offset]['portno'] = $matches[3]; $servers[$offset]['url'] = $matches[4]; $servers[$offset]['latitude'] = $matches[5]; $servers[$offset]['longitude'] = $matches[6]; $servers[$offset]['name'] = $matches[7]; } return ($servers); case 401: $this->messages[] = "401: No Site Information Available."; return (FALSE); default: return ($this->errors($code)); } } function status() { // Extract server status information $this->send("stat"); switch ($code = $this->code($this->parse(1))) { case 210: $this->messages[] = "210: OK, Status Information Follows."; return ($this->parse(0)); default: return ($this->errors($code)); } } function update() { // Ask server to update the database. $this->send("update"); switch ($code = $this->code($this->parse(1))) { case 200: $this->messages[] = "200: Updating the Database."; return (TRUE); case 401: $this->messages[] = "401: Permission Denied."; return (FALSE); case 402: $this->messages[] = "402: Unable to Update the Database."; return (FALSE); default: return ($this->errors($code)); } } function users() { // List all the current users attached to the server. $this->send("whom"); switch ($code = $this->code($this->parse(1))) { case 210: $this->messages[] = "210: OK, User List Follows."; return ($this->parse(0)); case 401: $this->messages[] = "401: No User Information Available."; return (FALSE); default: return ($this->errors($code)); } } function version() { // Request server software version information. $this->send("ver"); $header = $this->parse(1); switch ($code = $this->code($header)) { case 200: $this->messages[] = "200: Version Information."; $version[0] = $header; return ($version); case 201: $this->messages[] = "201: Version Information Follows."; $version = $this->parse(0); return ($version); default: return ($this->errors($code)); } } } ?>