Beginning Objective-C 2.0
I am new to software development and I would like to beginning programming in Cocoa.
I have downloaded Apple's Objective-C 2.0 Tutorial from the Developer Connection website, and I plan to read it before I begin reading a Cocoa tutorial written by Aaron Hillegass.
I currently only have knowledge of Java, and no prior experience with C. This means that I only have a background in object-oriented programming, as opposed to C, which is procedural.
Will I be able to comprehend Apple's tutorial? Should I obtain some knowledge on C before I begin reading the tutorial? Or should my knowledge of Java suffice?
Thank you!
The following links tell you about some of the improvements in ObjC 2.0 - I don't think that there is a lot to learn in addition to the "prior version" but some of the improvements are extremely nice to work with…
http://developer.apple.com/leopard/overview/objectivec2.html
http://theocacao.com/document.page/510
Andreas
Similar Messages
-
Hello.
This program is supposed to pull values from a table using a loop, and in the loop, put the values in objects in a varray. I'm new to objects and am stumped trying to get this program to run. When I attempt to run it in SQL*Plus I get the following feedback:
Type created.
Type body created
SP2-0552: Bind variable "MY_VARRAY_EMP1" not declared.
I don't think I even need a bind variable. Any feedback would be appreciated. Here's the program:
-- Enable screen I/O
SET SERVEROUTPUT ON SIZE 1000000
SET VERIFY OFF
-- begin object spec
CREATE OR REPLACE TYPE employee3 AS OBJECT
ename CHAR (20 char),
empno NUMBER (4),
sal NUMBER (10),
MEMBER FUNCTION get_ename RETURN CHAR, MEMBER PROCEDURE set_ename (SELF IN OUT NOCOPY employee3),
MEMBER FUNCTION get_empno RETURN NUMBER, MEMBER PROCEDURE set_empno (SELF IN OUT NOCOPY employee3),
MEMBER FUNCTION get_sal RETURN NUMBER, MEMBER PROCEDURE set_sal (SELF IN OUT NOCOPY employee3)
-- begin object body
CREATE OR REPLACE TYPE BODY employee3 AS
-- gets
MEMBER FUNCTION get_ename RETURN CHAR IS
BEGIN
RETURN self.ename;
END;
MEMBER FUNCTION get_empno RETURN NUMBER IS
BEGIN
RETURN self.empno;
END;
MEMBER FUNCTION get_sal RETURN NUMBER IS
BEGIN
RETURN self.ename;
END;
-- sets
MEMBER PROCEDURE set_ename(SELF IN OUT employee3) IS
BEGIN
self.ename := ename;
END;
MEMBER PROCEDURE set_empno(SELF IN OUT employee3) IS
BEGIN
self.empno := empno;
END;
MEMBER PROCEDURE set_sal(SELF IN OUT employee3) IS
BEGIN
self.sal := sal;
END;
END;
DECLARE
TYPE emp_varray IS VARRAY(10) OF EMPLOYEE3;
my_varray_emp1 EMP_VARRAY;
-- List of EMPNO's in order of appearance in EMP table (for cross-referencing, single-line retrieval)
TYPE MYCREF_VARRAY IS VARRAY(10) OF NUMBER(4);
varray_mycref MYCREF_VARRAY := MYCREF_VARRAY(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
this_object EMPLOYEE3;
-- make a variable to store one empno
thisno NUMBER(4);
-- make a counter
counter INT;
-- query variables for the set calls
q_ename CHAR(20 CHAR);
q_empno NUMBER(4);
q_sal NUMBER(10);
my_result INT;
BEGIN
--my_varray_emp1 := EMP_VARRAY(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
-- Put the first 10 EMPNO's in my cref array
SELECT empno BULK COLLECT INTO varray_mycref FROM emp WHERE ROWNUM < 11;
-- Use a loop to retrieve the first 10 objects in the "emp" table and put them in the varray of objects
q_ename := NULL;
q_empno := NULL;
q_sal := NULL;
my_result := NULL;
this_object := NULL;
counter := 1;
FOR counter IN 1..10 LOOP
thisno := varray_mycref(counter);
this_object := my_varray_emp1(counter);
SELECT ename INTO q_ename FROM emp WHERE empno = thisno;
my_result := this_object.set_ename(q_ename, NULL);
SELECT empno INTO q_empno FROM emp WHERE empno = thisno;
my_result := this_object.set_empno(q_empno, NULL);
SELECT sal INTO q_sal FROM emp WHERE empno = thisno;
my_result := this_object.set_sal(q_sal, NULL);
END LOOP;
-- Use another loop to display the information in the reverse order.
FOR counter in REVERSE 1..10 LOOP
this_object =: my_varray_emp1(counter);
dbms_output.put_line((this_object.get_ename()) || CHR(9) || (this_object.get_empno()) || CHR(9) || (this_object.get_sal()));
END LOOP;
END;Cleaning up your code for errors and eliminating unnecessary complexity...
Add a user-defined constructor which takes all attributes and calls the "setter" procedures in one trip:
-- Enable screen I/O
set SERVEROUTPUT on size 1000000
set VERIFY off
-- begin object spec
create or replace type employee3 as object
ename CHAR (20 char),
empno NUMBER (4),
sal NUMBER (10),
constructor function employee3(
self in out nocopy employee3,
aEname in char,
aEmpNo in integer,
aSal in number
return self as result,
member function get_ename return CHAR, member procedure set_ename (SELF in out nocopy employee3, ename in char),
member function get_empno return NUMBER, member procedure set_empno (SELF in out nocopy employee3, empno in integer),
member function get_sal return NUMBER, member procedure set_sal (SELF in out nocopy employee3, sal in integer)
-- begin object body
create or replace type body employee3 as
constructor function employee3(
self in out nocopy employee3,
aEname in char,
aEmpNo in integer,
aSal in number
return self as result
is
begin
self.set_ename(aEname);
self.set_empno(aEmpNo);
self.set_sal(aSal);
return;
end;
-- gets
member function get_ename return CHAR is
begin
return self.ename;
end;
member function get_empno return NUMBER is
begin
return self.empno;
end;
member function get_sal return NUMBER is
begin
return self.sal;
end;
-- sets
member procedure set_ename(SELF in out employee3, ename in char) is
begin
self.ename := ename;
end;
member procedure set_empno(SELF in out employee3, empno in integer) is
begin
self.empno := empno;
end;
member procedure set_sal(SELF in out employee3, sal in integer) is
begin
self.sal := sal;
end;
end;
(Since I don't have EMP handy at the moment, create a simple view instead)
create or replace view emp
as
select 'EMP' || to_char(level) ename
, level + 100 empno
, DBMS_RANDOM.VALUE(25000,75000) sal
from DUAL
connect by
level <= 20
Get rid of your loop and individual SELECTs, and replace it with a single SELECT BULK COLLECT INTO...
declare
type emp_varray is varray(10) of EMPLOYEE3;
my_varray_emp1 EMP_VARRAY;
this_object EMPLOYEE3;
begin
-- No need for a loop. Use SELECT BULK COLLECT INTO, together with a user-defined constructor call (since the
-- user-defined constructor overrides the default constructor we need to call it using named-parameter notation):
select new employee3(
aEname => e.ename,
aEmpNo => e.empno,
aSal => e.sal
bulk collect into
my_varray_emp1
from emp e
where rownum <= 10;
-- Use another loop to display the information in the reverse order.
for counter in reverse 1..10 loop
this_object := my_varray_emp1(counter);
dbms_output.put_line((this_object.get_ename()) || chr(9) || to_char(this_object.get_empno()) || chr(9) || to_char(this_object.get_sal()));
end loop;
end;
EMP10
110 60110
EMP9
109 67485
EMP8
108 58242
EMP7
107 47597
EMP6
106 58995
EMP5
105 49098
EMP4
104 47406
EMP3
103 67574
EMP2
102 59663
EMP1
101 52929
PL/SQL procedure successfully completed.
Gerard -
Hello,
I am starting to look into how to work with graphics in Java for the first time. So what I am trying to achieve is a simple circle moving across a frame.
Here is the code that I thought would do the trick.
package com.game.begin;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Begin extends JPanel
int x_pos = 10;
int y_pos = 100;
int radius = 20;
JFrame f = new JFrame();
public static void main(String[] args){
Begin b=new Begin();
b.doRun();
public void doRun(){
f.setSize(600,600 + 20);
f.setVisible(true);
f.setTitle("Do Title");
f.setContentPane(new Begin());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Graphics g=f.getGraphics();
while (true){
x_pos ++;
System.out.println("x="+x_pos+" y="+y_pos);
repaint();
// paint(g);
try {
Thread.sleep (10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
public void paint (Graphics g)
System.out.println("paint method of my thread..............");
g.setColor (Color.red);
g.fillOval (x_pos - radius, y_pos - radius, 2 * radius, 2 * radius);
}However all I get is a circle. It doesn't move across a screen. When I uncomment
// Graphics g=f.getGraphics();and
// paint(g);lines . I get a big red line moving across the screen. Basically I draw a new circle without erasing an old one. My understanding is that if I utilize repaint method Java will automatically erase old graphic and replace with the new one.
I am not sure why in my case this doesn't happen. Can you explain what's going on and/or correct the above code?
Thank you.import java.awt.*;
import javax.swing.*;
public class Begin extends JPanel
int x_pos = 10;
int y_pos = 100;
int radius = 20;
JFrame f = new JFrame();
public static void main(String[] args){
Begin b=new Begin();
b.doRun();
public void doRun(){
f.setSize(600,600 + 20);
f.setVisible(true);
f.setTitle("Do Title");
// Why create a new Begin object?
f.setContentPane(this);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Never do this! Have the code render only when asked to do so.
// Graphics g=f.getGraphics();
while (true){
x_pos ++;
System.out.println("x="+x_pos+" y="+y_pos);
repaint();
try {
// It is bad practice to block the EDT. Invoke this loop from a Timer instead.
Thread.sleep (10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// Call paint() for AWT. Call paintComponent() for Swing.
public void paintComponent (Graphics g)
// Will erase the background!
super.paintComponent(g);
System.out.println("paint method of my thread..............");
g.setColor (Color.red);
g.fillOval (x_pos - radius, y_pos - radius, 2 * radius, 2 * radius);
}The more expert GUI developers could probably point you to the exact parts of the Java Tutorial that cover custom rendering and animation. But I could not be bothered googling them. -
Updating Transient objects in Kodo 2.5.5
I have a situation where I construct a JDO object in transient state in my
code ( for batch processing of data from a file into the database) by
calling the objects contructor and setting it's values. The row
representing this object may or may not exist in the database.
How do I make the object peristant ? If the row already exists, then I
must be able to update the row with the new values ( non-primary keys ).
If not, I should insert a new row.
There are no multi table relationships involved in this case. A JDO object
represents just one table.
We want to avoid the scheme which involves retrieve the object first and
then trying to update in a transaction.
AdarshTransaction t = kpm.currentTransaction();
try {
MyObject o = new MyObject(...)
t.begin();
Object id = ((PersistenceCapable)o).jdoNewObjectIdInstance();
((PersistenceCapable)o).jdoCopyKeyFieldsToObjectId(id);
try{
System.out.println(id);
Object trio = pm.getObjectById(id,true);
pm.deletePersistent(trio);
}catch(ObjectNotFoundException oe){
System.out.println("First time!");
pm.makePersistent(o);
t.commit();
}catch(...){ -
Hi everybody,
I have the next trouble, I need to clone an Object, but the method "clone()" in the Object class is protected.
I am working with a DBMSOO that provide me the following classes: Database, Transaction. I want to have a generic command that retrieve Objects from a database Object-Oriented, and then to make a cast to a specific class.
This is the code:
public class Lookup
private Object object;
public Lookup
Database db = new Database();
db.open( "dbUrl->server", Database.OPEN_READ_ONLY );
Transaction txn = new Transaction( db );
txn.begin();
object = db.lookup( "idObject" );
txn.commit();
db.close();
public Object getObject() {
return object;
My trouble is that when the Transaction is finished with commit() method, the object reference is null. I thought to clone the Object, but is not posible.
Could anyone help me, please?
Sincerely,
Alvaro
PS: Sorry, for my english. I know it isn't very good.Hi DrClap,
I understand you, but if I don't write the sentence:
txn.commit()
that close the Transaction, the reference "object" isn't null.
What's the matter?
Thanks a lot for your interesting.
Alvaro -
Hi,
1-how can I see the objects of a tablespace ?
2-does TEMP tablespace contain any object ? How to see ?
Thanks.Many thanks but :
SP2-0734: unknown command beginning "'free spac..." - rest of line ignored.
SP2-0734: unknown command beginning "' ' object..." - rest of line ignored.
SP2-0734: unknown command beginning "file_id, /..." - rest of line ignored.
SP2-0734: unknown command beginning "block_id, ..." - rest of line ignored.
SP2-0044: For a list of known commands enter HELP
and to leave enter EXIT.
SP2-0734: unknown command beginning "CEIL(block..." - rest of line ignored.
SP2-0734: unknown command beginning "from dba_f..." - rest of line ignored.
SP2-0734: unknown command beginning "where tabl..." - rest of line ignored.
SP2-0042: unknown command "union" - rest of line ignored.
SP2-0044: For a list of known commands enter HELP
and to leave enter EXIT.
SP2-0734: unknown command beginning "substr(own..." - rest of line ignored.
SP2-0734: unknown command beginning "substr(seg..." - rest of line ignored.
SP2-0734: unknown command beginning "file_id, /..." - rest of line ignored.
SP2-0734: unknown command beginning "block_id, ..." - rest of line ignored.
SP2-0044: For a list of known commands enter HELP
and to leave enter EXIT.
SP2-0734: unknown command beginning "CEIL(block..." - rest of line ignored.
SP2-0734: unknown command beginning "from dba_e..." - rest of line ignored.
SP2-0734: unknown command beginning "where tabl..." - rest of line ignored.
SP2-0734: unknown command beginning "order by 1..." - rest of line ignored.
SP2-0044: For a list of known commands enter HELP
and to leave enter EXIT.
select tablespace_name,
ERROR at line 1:
ORA-00936: missing expression
Usage: { EXIT | QUIT } [ SUCCESS | FAILURE | WARNING | n |
<variable> | :<bindvariable> ] [ COMMIT | ROLLBACK ]
Message was edited by:
user522961 -
Most mpd.class.php's are old and produce a lot of errors which caused me much frustration in this thread.
I was wrapping my head around why phpmpreloaded worked and the others never and it's because it uses an updated mpd.class.php. To save others the frustration and hassle I figured I'd post the new class here.
Enjoy.
<?php
* Sven Ginka 03/2010
* Version mpd.class.php-1.3
* - take over from Hendrik Stoetter
* - removed "split()" as this function is marked depracted
* - added property "xfade" (used by IPodMp, phpMp+)
* - added property "bitrate" (used by phpMp+)
* - added define "MPD_SEARCH_FILENAME"
* - included sorting algorithm "msort"
* - added function validateFile() for guessing a title if no ID3 data is given
* Hendrik Stoetter 03/2008
* - this a lightly modified version of mod.class Version 1.2.
* - fixed some bugs and added some new functions
* - Changes:
* GetDir($url) -> GetDir(url,$sort)
* var $stats
* Benjamin Carlisle 05/05/2004
* mpd.class.php - PHP Object Interface to the MPD Music Player Daemon
* Version 1.2, Released 05/05/2004
* Copyright (C) 2003-2004 Benjamin Carlisle ([email protected])
* http://mpd.24oz.com/ | http://www.musicpd.org/
* 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
// Create common command definitions for MPD to use
define("MPD_CMD_STATUS", "status");
define("MPD_CMD_STATISTICS", "stats");
define("MPD_CMD_VOLUME", "volume");
define("MPD_CMD_SETVOL", "setvol");
define("MPD_CMD_PLAY", "play");
define("MPD_CMD_STOP", "stop");
define("MPD_CMD_PAUSE", "pause");
define("MPD_CMD_NEXT", "next");
define("MPD_CMD_PREV", "previous");
define("MPD_CMD_PLLIST", "playlistinfo");
define("MPD_CMD_PLADD", "add");
define("MPD_CMD_PLREMOVE", "delete");
define("MPD_CMD_PLCLEAR", "clear");
define("MPD_CMD_PLSHUFFLE", "shuffle");
define("MPD_CMD_PLLOAD", "load");
define("MPD_CMD_PLSAVE", "save");
define("MPD_CMD_KILL", "kill");
define("MPD_CMD_REFRESH", "update");
define("MPD_CMD_REPEAT", "repeat");
define("MPD_CMD_LSDIR", "lsinfo");
define("MPD_CMD_SEARCH", "search");
define("MPD_CMD_START_BULK", "command_list_begin");
define("MPD_CMD_END_BULK", "command_list_end");
define("MPD_CMD_FIND", "find");
define("MPD_CMD_RANDOM", "random");
define("MPD_CMD_SEEK", "seek");
define("MPD_CMD_PLSWAPTRACK", "swap");
define("MPD_CMD_PLMOVETRACK", "move");
define("MPD_CMD_PASSWORD", "password");
define("MPD_CMD_TABLE", "list");
define("MPD_CMD_PLMOVE", "move" );
// Predefined MPD Response messages
define("MPD_RESPONSE_ERR", "ACK");
define("MPD_RESPONSE_OK", "OK");
// MPD State Constants
define("MPD_STATE_PLAYING", "play");
define("MPD_STATE_STOPPED", "stop");
define("MPD_STATE_PAUSED", "pause");
// MPD Searching Constants
define("MPD_SEARCH_ARTIST", "artist");
define("MPD_SEARCH_TITLE", "title");
define("MPD_SEARCH_ALBUM", "album");
define("MPD_SEARCH_ANY", "any");
define("MPD_SEARCH_FILENAME","filename");
// MPD Cache Tables
define("MPD_TBL_ARTIST","artist");
define("MPD_TBL_ALBUM","album");
$mpd_debug = 0;
function addLog($text){
global $mpd_debug;
$style="background-color:lightgrey;border:thin solid grey;margin:5px;padding:5px";
if ($mpd_debug) echo '<div style="'.$style.'">log:>'.$text.'</div>';
function addErr($err){
global $mpd_debug;
if ($mpd_debug) echo 'error:>'.$err.'<br>';
class mpd {
// TCP/Connection variables
var $host;
var $port;
var $password;
var $mpd_sock = NULL;
var $connected = FALSE;
// MPD Status variables
var $mpd_version = "(unknown)";
var $state;
var $current_track_position;
var $current_track_length;
var $current_track_id;
var $volume;
var $repeat;
var $random;
var $uptime;
var $playtime;
var $db_last_refreshed;
var $num_songs_played;
var $playlist_count;
var $xfade;
var $bitrate;
var $num_artists;
var $num_albums;
var $num_songs;
var $playlist = array();
var $stats;
// Misc Other Vars
var $mpd_class_version = "1.2";
var $debugging = FALSE; // Set to TRUE to turn extended debugging on.
var $errStr = ""; // Used for maintaining information about the last error message
var $command_queue; // The list of commands for bulk command sending
// =================== BEGIN OBJECT METHODS ================
/* mpd() : Constructor
* Builds the MPD object, connects to the server, and refreshes all local object properties.
function mpd($srv,$port,$pwd = NULL, $debug= FALSE ) {
$this->host = $srv;
$this->port = $port;
$this->password = $pwd;
$this->debugging = $debug;
global $mpd_debug;
$mpd_debug = $debug;
$resp = $this->Connect();
if ( is_null($resp) ) {
addErr( "Could not connect" );
return;
} else {
addLog( "connected");
list ( $this->mpd_version ) = sscanf($resp, MPD_RESPONSE_OK . " MPD %s\n");
if ( ! is_null($pwd) ) {
if ( is_null($this->SendCommand(MPD_CMD_PASSWORD,$pwd)) ) {
$this->connected = FALSE;
addErr("bad password");
return; // bad password or command
if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!
$this->connected = FALSE;
addErr("Password supplied does not have read access");
return;
} else {
if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!
$this->connected = FALSE;
addErr("Password required to access server");
return;
/* Connect()
* Connects to the MPD server.
* NOTE: This is called automatically upon object instantiation; you should not need to call this directly.
function Connect() {
addLog( "mpd->Connect() / host: ".$this->host.", port: ".$this->port."\n" );
$this->mpd_sock = fsockopen($this->host,$this->port,$errNo,$errStr,10);
if (!$this->mpd_sock) {
addErr("Socket Error: $errStr ($errNo)");
return NULL;
} else {
$counter=0;
while(!feof($this->mpd_sock)) {
$counter++;
if ($counter > 10){
addErr("no file end");
return NULL;
$response = fgets($this->mpd_sock,1024);
addLog( $response );
if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {
$this->connected = TRUE;
return $response;
if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {
// close socket
fclose($this->mpd_sock);
addErr("Server responded with: $response");
return NULL;
// close socket
fclose($this->mpd_sock);
// Generic response
addErr("Connection not available");
return NULL;
/* SendCommand()
* Sends a generic command to the MPD server. Several command constants are pre-defined for
* use (see MPD_CMD_* constant definitions above).
function SendCommand($cmdStr,$arg1 = "",$arg2 = "") {
addLog("mpd->SendCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2 );
// Clear out the error String
$this->errStr = NULL;
$respStr = "";
if ( ! $this->connected ) {
addErr( "mpd->SendCommand() / Error: Not connected");
} else {
// Check the command compatibility:
if ( ! $this->_checkCompatibility($cmdStr) ) {
return NULL;
if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";
if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";
fputs($this->mpd_sock,"$cmdStr\n");
while(!feof($this->mpd_sock)) {
$response = fgets($this->mpd_sock,1024);
//addLog($response);
// An OK signals the end of transmission -- we'll ignore it
if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {
break;
// An ERR signals the end of transmission with an error! Let's grab the single-line message.
if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {
list ( $junk, $errTmp ) = strtok(MPD_RESPONSE_ERR . " ",$response );
addErr( strtok($errTmp,"\n") );
return NULL;
// Build the response string
$respStr .= $response;
addLog("mpd->SendCommand() / response: '".$respStr."'\n");
return $respStr;
/* QueueCommand()
* Queues a generic command for later sending to the MPD server. The CommandQueue can hold
* as many commands as needed, and are sent all at once, in the order they are queued, using
* the SendCommandQueue() method. The syntax for queueing commands is identical to SendCommand().
function QueueCommand($cmdStr,$arg1 = "",$arg2 = "") {
if ( $this->debugging ) echo "mpd->QueueCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";
if ( ! $this->connected ) {
echo "mpd->QueueCommand() / Error: Not connected\n";
return NULL;
} else {
if ( strlen($this->command_queue) == 0 ) {
$this->command_queue = MPD_CMD_START_BULK . "\n";
if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";
if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";
$this->command_queue .= $cmdStr ."\n";
if ( $this->debugging ) echo "mpd->QueueCommand() / return\n";
return TRUE;
/* SendCommandQueue()
* Sends all commands in the Command Queue to the MPD server. See also QueueCommand().
function SendCommandQueue() {
if ( $this->debugging ) echo "mpd->SendCommandQueue()\n";
if ( ! $this->connected ) {
echo "mpd->SendCommandQueue() / Error: Not connected\n";
return NULL;
} else {
$this->command_queue .= MPD_CMD_END_BULK . "\n";
if ( is_null($respStr = $this->SendCommand($this->command_queue)) ) {
return NULL;
} else {
$this->command_queue = NULL;
if ( $this->debugging ) echo "mpd->SendCommandQueue() / response: '".$respStr."'\n";
return $respStr;
/* AdjustVolume()
* Adjusts the mixer volume on the MPD by <modifier>, which can be a positive (volume increase),
* or negative (volume decrease) value.
function AdjustVolume($modifier) {
if ( $this->debugging ) echo "mpd->AdjustVolume()\n";
if ( ! is_numeric($modifier) ) {
$this->errStr = "AdjustVolume() : argument 1 must be a numeric value";
return NULL;
$this->RefreshInfo();
$newVol = $this->volume + $modifier;
$ret = $this->SetVolume($newVol);
if ( $this->debugging ) echo "mpd->AdjustVolume() / return\n";
return $ret;
/* SetVolume()
* Sets the mixer volume to <newVol>, which should be between 1 - 100.
function SetVolume($newVol) {
if ( $this->debugging ) echo "mpd->SetVolume()\n";
if ( ! is_numeric($newVol) ) {
$this->errStr = "SetVolume() : argument 1 must be a numeric value";
return NULL;
// Forcibly prevent out of range errors
if ( $newVol < 0 ) $newVol = 0;
if ( $newVol > 100 ) $newVol = 100;
// If we're not compatible with SETVOL, we'll try adjusting using VOLUME
if ( $this->_checkCompatibility(MPD_CMD_SETVOL) ) {
if ( ! is_null($ret = $this->SendCommand(MPD_CMD_SETVOL,$newVol))) $this->volume = $newVol;
} else {
$this->RefreshInfo(); // Get the latest volume
if ( is_null($this->volume) ) {
return NULL;
} else {
$modifier = ( $newVol - $this->volume );
if ( ! is_null($ret = $this->SendCommand(MPD_CMD_VOLUME,$modifier))) $this->volume = $newVol;
if ( $this->debugging ) echo "mpd->SetVolume() / return\n";
return $ret;
/* GetDir()
* Retrieves a database directory listing of the <dir> directory and places the results into
* a multidimensional array. If no directory is specified, the directory listing is at the
* base of the MPD music path.
function GetDir($dir = "",$sort = "") {
addLog( "mpd->GetDir()" );
$resp = $this->SendCommand(MPD_CMD_LSDIR,$dir);
$listArray = $this->_parseFileListResponse($resp);
if ($listArray==null){
return null;
// we have 3 differnt items: directory, playlist and file
// we have to sort them individually and separate
// playlist and directory by name
// file by $sort
// 1st: subarrays
$array_directory = $listArray['directories'];
$array_playlist = $listArray['playlists'];
$array_file = $listArray['files'];
// 2nd: sort them
natcasesort($array_directory);
natcasesort($array_playlist);
usort($array_file,"msort");
// 3rd: rebuild
$array_return= array(
"directories"=> $array_directory,
"playlists"=> $array_playlist,
"files"=> $array_file
foreach ($array_directory as $value) {
$array_return[]["directory"] = $value;
foreach ($array_playlist as $value) {
$array_return[]["playlist"] = $value;
$array_return = array_merge($array_return,$array_file);
addLog( "mpd->GetDir() / return ".print_r($array_return,true));
return $array_return;
/* GetDirTest() (Unoffical add) -- Returns readable dir contents
* Retrieves a database directory listing of the <dir> directory and places the results into
* a multidimensional array. If no directory is specified, the directory listing is at the
* base of the MPD music path.
function GetDirTest($dir = "") {
if ( $this->debugging ) echo "mpd->GetDir()\n";
$resp = $this->SendCommand(MPD_CMD_LSDIR,$dir);
#$dirlist = $this->_parseFileListResponse($resp);
$dirlist = $this->_parseFileListResponseHumanReadable($resp);
if ( $this->debugging ) echo "mpd->GetDir() / return ".print_r($dirlist)."\n";
return $dirlist;
/* PLAdd()
* Adds each track listed in a single-dimensional <trackArray>, which contains filenames
* of tracks to add, to the end of the playlist. This is used to add many, many tracks to
* the playlist in one swoop.
function PLAddBulk($trackArray) {
if ( $this->debugging ) echo "mpd->PLAddBulk()\n";
$num_files = count($trackArray);
for ( $i = 0; $i < $num_files; $i++ ) {
$this->QueueCommand(MPD_CMD_PLADD,$trackArray[$i]);
$resp = $this->SendCommandQueue();
$this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLAddBulk() / return\n";
return $resp;
/* PLAdd()
* Adds the file <file> to the end of the playlist. <file> must be a track in the MPD database.
function PLAdd($fileName) {
if ( $this->debugging ) echo "mpd->PLAdd()\n";
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,$fileName))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLAdd() / return\n";
return $resp;
/* PLMoveTrack()
* Moves track number <origPos> to position <newPos> in the playlist. This is used to reorder
* the songs in the playlist.
function PLMoveTrack($origPos, $newPos) {
if ( $this->debugging ) echo "mpd->PLMoveTrack()\n";
if ( ! is_numeric($origPos) ) {
$this->errStr = "PLMoveTrack(): argument 1 must be numeric";
return NULL;
if ( $origPos < 0 or $origPos > $this->playlist_count ) {
$this->errStr = "PLMoveTrack(): argument 1 out of range";
return NULL;
if ( $newPos < 0 ) $newPos = 0;
if ( $newPos > $this->playlist_count ) $newPos = $this->playlist_count;
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$origPos,$newPos))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLMoveTrack() / return\n";
return $resp;
/* PLShuffle()
* Randomly reorders the songs in the playlist.
function PLShuffle() {
if ( $this->debugging ) echo "mpd->PLShuffle()\n";
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLSHUFFLE))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLShuffle() / return\n";
return $resp;
/* PLLoad()
* Retrieves the playlist from <file>.m3u and loads it into the current playlist.
function PLLoad($file) {
if ( $this->debugging ) echo "mpd->PLLoad()\n";
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLLOAD,$file))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLLoad() / return\n";
return $resp;
/* PLSave()
* Saves the playlist to <file>.m3u for later retrieval. The file is saved in the MPD playlist
* directory.
function PLSave($file) {
if ( $this->debugging ) echo "mpd->PLSave()\n";
$resp = $this->SendCommand(MPD_CMD_PLSAVE,$file);
if ( $this->debugging ) echo "mpd->PLSave() / return\n";
return $resp;
/* PLClear()
* Empties the playlist.
function PLClear() {
if ( $this->debugging ) echo "mpd->PLClear()\n";
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLCLEAR))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLClear() / return\n";
return $resp;
/* PLRemove()
* Removes track <id> from the playlist.
function PLRemove($id) {
if ( $this->debugging ) echo "mpd->PLRemove()\n";
if ( ! is_numeric($id) ) {
$this->errStr = "PLRemove() : argument 1 must be a numeric value";
return NULL;
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLREMOVE,$id))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLRemove() / return\n";
return $resp;
/* SetRepeat()
* Enables 'loop' mode -- tells MPD continually loop the playlist. The <repVal> parameter
* is either 1 (on) or 0 (off).
function SetRepeat($repVal) {
if ( $this->debugging ) echo "mpd->SetRepeat()\n";
$rpt = $this->SendCommand(MPD_CMD_REPEAT,$repVal);
$this->repeat = $repVal;
if ( $this->debugging ) echo "mpd->SetRepeat() / return\n";
return $rpt;
/* SetRandom()
* Enables 'randomize' mode -- tells MPD to play songs in the playlist in random order. The
* <rndVal> parameter is either 1 (on) or 0 (off).
function SetRandom($rndVal) {
if ( $this->debugging ) echo "mpd->SetRandom()\n";
$resp = $this->SendCommand(MPD_CMD_RANDOM,$rndVal);
$this->random = $rndVal;
if ( $this->debugging ) echo "mpd->SetRandom() / return\n";
return $resp;
/* Shutdown()
* Shuts down the MPD server (aka sends the KILL command). This closes the current connection,
* and prevents future communication with the server.
function Shutdown() {
if ( $this->debugging ) echo "mpd->Shutdown()\n";
$resp = $this->SendCommand(MPD_CMD_SHUTDOWN);
$this->connected = FALSE;
unset($this->mpd_version);
unset($this->errStr);
unset($this->mpd_sock);
if ( $this->debugging ) echo "mpd->Shutdown() / return\n";
return $resp;
/* DBRefresh()
* Tells MPD to rescan the music directory for new tracks, and to refresh the Database. Tracks
* cannot be played unless they are in the MPD database.
function DBRefresh() {
if ( $this->debugging ) echo "mpd->DBRefresh()\n";
$resp = $this->SendCommand(MPD_CMD_REFRESH);
// Update local variables
$this->RefreshInfo();
if ( $this->debugging ) echo "mpd->DBRefresh() / return\n";
return $resp;
/* Play()
* Begins playing the songs in the MPD playlist.
function Play() {
if ( $this->debugging ) echo "mpd->Play()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY) )) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Play() / return\n";
return $rpt;
/* Stop()
* Stops playing the MPD.
function Stop() {
if ( $this->debugging ) echo "mpd->Stop()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_STOP) )) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Stop() / return\n";
return $rpt;
/* Pause()
* Toggles pausing on the MPD. Calling it once will pause the player, calling it again
* will unpause.
function Pause() {
if ( $this->debugging ) echo "mpd->Pause()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PAUSE) )) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Pause() / return\n";
return $rpt;
/* SeekTo()
* Skips directly to the <idx> song in the MPD playlist.
function SkipTo($idx) {
if ( $this->debugging ) echo "mpd->SkipTo()\n";
if ( ! is_numeric($idx) ) {
$this->errStr = "SkipTo() : argument 1 must be a numeric value";
return NULL;
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY,$idx))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->SkipTo() / return\n";
return $idx;
/* SeekTo()
* Skips directly to a given position within a track in the MPD playlist. The <pos> argument,
* given in seconds, is the track position to locate. The <track> argument, if supplied is
* the track number in the playlist. If <track> is not specified, the current track is assumed.
function SeekTo($pos, $track = -1) {
if ( $this->debugging ) echo "mpd->SeekTo()\n";
if ( ! is_numeric($pos) ) {
$this->errStr = "SeekTo() : argument 1 must be a numeric value";
return NULL;
if ( ! is_numeric($track) ) {
$this->errStr = "SeekTo() : argument 2 must be a numeric value";
return NULL;
if ( $track == -1 ) {
$track = $this->current_track_id;
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_SEEK,$track,$pos))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->SeekTo() / return\n";
return $pos;
/* Next()
* Skips to the next song in the MPD playlist. If not playing, returns an error.
function Next() {
if ( $this->debugging ) echo "mpd->Next()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_NEXT))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Next() / return\n";
return $rpt;
/* Previous()
* Skips to the previous song in the MPD playlist. If not playing, returns an error.
function Previous() {
if ( $this->debugging ) echo "mpd->Previous()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PREV))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Previous() / return\n";
return $rpt;
/* Search()
* Searches the MPD database. The search <type> should be one of the following:
* MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM
* The search <string> is a case-insensitive locator string. Anything that contains
* <string> will be returned in the results.
function Search($type,$string) {
addLog("mpd->Search()");
if ( $type != MPD_SEARCH_ARTIST and
$type != MPD_SEARCH_ALBUM and
$type != MPD_SEARCH_ANY and
$type != MPD_SEARCH_TITLE ) {
addErr( "mpd->Search(): invalid search type" );
return NULL;
} else {
if ( is_null($resp = $this->SendCommand(MPD_CMD_SEARCH,$type,$string))) return NULL;
$searchlist = $this->_parseFileListResponse($resp);
addLog( "mpd->Search() / return ".print_r($searchlist,true) );
return $searchlist;
/* Find()
* Find() looks for exact matches in the MPD database. The find <type> should be one of
* the following:
* MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM
* The find <string> is a case-insensitive locator string. Anything that exactly matches
* <string> will be returned in the results.
function Find($type,$string) {
if ( $this->debugging ) echo "mpd->Find()\n";
if ( $type != MPD_SEARCH_ARTIST and
$type != MPD_SEARCH_ALBUM and
$type != MPD_SEARCH_TITLE ) {
$this->errStr = "mpd->Find(): invalid find type";
return NULL;
} else {
if ( is_null($resp = $this->SendCommand(MPD_CMD_FIND,$type,$string))) return NULL;
$searchlist = $this->_parseFileListResponse($resp);
if ( $this->debugging ) echo "mpd->Find() / return ".print_r($searchlist)."\n";
return $searchlist;
/* Disconnect()
* Closes the connection to the MPD server.
function Disconnect() {
if ( $this->debugging ) echo "mpd->Disconnect()\n";
fclose($this->mpd_sock);
$this->connected = FALSE;
unset($this->mpd_version);
unset($this->errStr);
unset($this->mpd_sock);
/* GetArtists()
* Returns the list of artists in the database in an associative array.
function GetArtists() {
if ( $this->debugging ) echo "mpd->GetArtists()\n";
if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ARTIST))) return NULL;
$arArray = array();
$arLine = strtok($resp,"\n");
$arName = "";
$arCounter = -1;
while ( $arLine ) {
list ( $element, $value ) = explode(": ",$arLine);
if ( $element == "Artist" ) {
$arCounter++;
$arName = $value;
$arArray[$arCounter] = $arName;
$arLine = strtok("\n");
if ( $this->debugging ) echo "mpd->GetArtists()\n";
return $arArray;
/* GetAlbums()
* Returns the list of albums in the database in an associative array. Optional parameter
* is an artist Name which will list all albums by a particular artist.
function GetAlbums( $ar = NULL) {
if ( $this->debugging ) echo "mpd->GetAlbums()\n";
if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ALBUM, $ar ))) return NULL;
$alArray = array();
$alLine = strtok($resp,"\n");
$alName = "";
$alCounter = -1;
while ( $alLine ) {
list ( $element, $value ) = explode(": ",$alLine);
if ( $element == "Album" ) {
$alCounter++;
$alName = $value;
$alArray[$alCounter] = $alName;
$alLine = strtok("\n");
if ( $this->debugging ) echo "mpd->GetAlbums()\n";
return $alArray;
//***************************** INTERNAL FUNCTIONS ******************************//
/* _computeVersionValue()
* Computes a compatibility value from a version string
private function _computeVersionValue($verStr) {
list ($ver_maj, $ver_min, $ver_rel ) = explode(".",$verStr);
return ( 100 * $ver_maj ) + ( 10 * $ver_min ) + ( $ver_rel );
/* _checkCompatibility()
* Check MPD command compatibility against our internal table. If there is no version
* listed in the table, allow it by default.
private function _checkCompatibility($cmd) {
// Check minimum compatibility
if (isset($this->COMPATIBILITY_MIN_TBL[$cmd])){
$req_ver_low = $this->COMPATIBILITY_MIN_TBL[$cmd];
} else {
$req_ver_low = "0.9.1";
// check max compatibility
if (isset($this->COMPATIBILITY_MAX_TBL[$cmd])){
$req_ver_hi = $this->COMPATIBILITY_MAX_TBL[$cmd];
} else {
$req_ver_hi = "0.20.0";
$mpd_ver = $this->_computeVersionValue($this->mpd_version);
if ( $req_ver_low ) {
$req_ver = $this->_computeVersionValue($req_ver_low);
if ( $mpd_ver < $req_ver ) {
addErr("Command '$cmd' is not compatible with this version of MPD, version ".$req_ver_low." required");
return FALSE;
// Check maximum compatibility -- this will check for deprecations
if ( $req_ver_hi ) {
$req_ver = $this->_computeVersionValue($req_ver_hi);
if ( $mpd_ver > $req_ver ) {
addErr("Command '$cmd' has been deprecated in this version of MPD.");
return FALSE;
return TRUE;
* checks the file entry and complete it if necesarry
* checked fields are 'Artist', 'Genre' and 'Title'
private function _validateFile( $fileItem ){
$filename = $fileItem['file'];
if (!isset($fileItem['Artist'])){ $fileItem['Artist']=null; }
if (!isset($fileItem['Genre'])){ $fileItem['Genre']=null; }
// special conversion for streams
if (stripos($filename, 'http' )!==false){
if (!isset($fileItem['Title'])) $title = ''; else $title=$fileItem['Title'];
if (!isset($fileItem['Name'])) $name = ''; else $name=$fileItem['Name'];
if (!isset($fileItem['Artist'])) $artist = ''; else $artist=$fileItem['Artist'];
if (strlen($title.$name.$artist)==0){
$fileItem['Title'] = $filename;
} else {
$fileItem['Title'] = 'stream://'.$title.' '.$name.' '.$artist;
if (!isset($fileItem['Title'])){
$file_parts = explode('/', $filename);
$fileItem['Title'] = $filename;
return $fileItem;
* take the response of mpd and split it up into
* items of types 'file', 'directory' and 'playlist'
private function _extractItems( $resp ){
if ( $resp == null ) {
addLog('empty file list');
return NULL;
// strip unwanted chars
$resp = trim($resp);
// split up into lines
$lineList = explode("\n", $resp );
$array = array();
$item=null;
foreach ($lineList as $line ){
list ( $element, $value ) = explode(": ",$line);
// if one of the key words come up, store the item
if (($element == "directory") or ($element=="playlist") or ($element=="file")){
if ($item){
$array[] = $item;
$item = array();
$item[$element] = $value;
// check if there is a last item to store
if (sizeof($item)>0){
$array[] = $item;
return $array;
/* _parseFileListResponse()
* Builds a multidimensional array with MPD response lists.
* NOTE: This function is used internally within the class. It should not be used.
private function _parseFileListResponse($resp) {
$valuesArray = $this->_extractItems( $resp );
if ($valuesArray == null ){
return null;
//1. create empty arrays
$directoriesArray = array();
$filesArray = array();
$playlistsArray = array();
//2. sort the items
foreach ( $valuesArray as $item ) {
if (isset($item['file'])){
$filesArray[] = $this->_validateFile($item);
} else if (isset($item['directory'])){
$directoriesArray[] = $item['directory'];
} else if (isset($item['playlist'])){
$playlistsArray[] = $item['playlist'];
} else {
addErr('should not enter this');
//3. create a combined list of items
$returnArray = array(
"directories"=>$directoriesArray,
"playlists"=>$playlistsArray,
"files"=>$filesArray
addLog( print_r($valuesArray,true) );
return $returnArray;
/* RefreshInfo()
* Updates all class properties with the values from the MPD server.
* NOTE: This function is automatically called upon Connect() as of v1.1.
function RefreshInfo() {
// Get the Server Statistics
$statStr = $this->SendCommand(MPD_CMD_STATISTICS);
if ( !$statStr ) {
return NULL;
} else {
$stats = array();
$statStr=trim($statStr);
$statLine = explode( "\n", $statStr );
foreach ( $statLine as $line ) {
list ( $element, $value ) = explode(": ",$line);
$stats[$element] = $value;
// Get the Server Status
$statusStr = $this->SendCommand(MPD_CMD_STATUS);
if ( ! $statusStr ) {
return NULL;
} else {
$status = array();
$statusStr=trim($statusStr);
$statusLine = explode("\n", $statusStr );
foreach ( $statusLine as $line ) {
list ( $element, $value ) = explode(": ",$line);
$status[$element] = $value;
// Get the Playlist
$plStr = $this->SendCommand(MPD_CMD_PLLIST);
$array = $this->_parseFileListResponse($plStr);
$playlist = $array['files'];
$this->playlist_count = count($playlist);
$this->playlist = array();
if (sizeof($playlist)>0){
foreach ($playlist as $item ){
$this->playlist[$item['Pos']]=$item;
// Set Misc Other Variables
$this->state = $status['state'];
if ( ($this->state == MPD_STATE_PLAYING) || ($this->state == MPD_STATE_PAUSED) ) {
$this->current_track_id = $status['song'];
list ($this->current_track_position, $this->current_track_length ) = explode(":",$status['time']);
} else {
$this->current_track_id = -1;
$this->current_track_position = -1;
$this->current_track_length = -1;
$this->repeat = $status['repeat'];
$this->random = $status['random'];
$this->db_last_refreshed = $stats['db_update'];
$this->volume = $status['volume'];
$this->uptime = $stats['uptime'];
$this->playtime = $stats['playtime'];
$this->num_songs_played = $stats['songs'];
$this->num_artists = $stats['artists'];
$this->num_songs = $stats['songs'];
$this->num_albums = $stats['albums'];
$this->xfade = $status['xfade'];
if(isset($status['bitrate'])) $this->bitrate = $status['bitrate'];
else $this->bitrate = FALSE;
return TRUE;
/* ------------------ DEPRECATED METHODS -------------------*/
/* GetStatistics()
* Retrieves the 'statistics' variables from the server and tosses them into an array.
* NOTE: This function really should not be used. Instead, use $this->[variable]. The function
* will most likely be deprecated in future releases.
function GetStatistics() {
if ( $this->debugging ) echo "mpd->GetStatistics()\n";
$stats = $this->SendCommand(MPD_CMD_STATISTICS);
if ( !$stats ) {
return NULL;
} else {
$statsArray = array();
$statsLine = strtok($stats,"\n");
while ( $statsLine ) {
list ( $element, $value ) = explode(": ",$statsLine);
$statsArray[$element] = $value;
$statsLine = strtok("\n");
if ( $this->debugging ) echo "mpd->GetStatistics() / return: " . print_r($statsArray) ."\n";
return $statsArray;
/* GetStatus()
* Retrieves the 'status' variables from the server and tosses them into an array.
* NOTE: This function really should not be used. Instead, use $this->[variable]. The function
* will most likely be deprecated in future releases.
function GetStatus() {
if ( $this->debugging ) echo "mpd->GetStatus()\n";
$status = $this->SendCommand(MPD_CMD_STATUS);
if ( ! $status ) {
return NULL;
} else {
$statusArray = array();
$statusLine = strtok($status,"\n");
while ( $statusLine ) {
list ( $element, $value ) = explode(": ",$statusLine);
$statusArray[$element] = $value;
$statusLine = strtok("\n");
if ( $this->debugging ) echo "mpd->GetStatus() / return: " . print_r($statusArray) ."\n";
return $statusArray;
/* GetVolume()
* Retrieves the mixer volume from the server.
* NOTE: This function really should not be used. Instead, use $this->volume. The function
* will most likely be deprecated in future releases.
function GetVolume() {
if ( $this->debugging ) echo "mpd->GetVolume()\n";
$volLine = $this->SendCommand(MPD_CMD_STATUS);
if ( ! $volLine ) {
return NULL;
} else {
list ($vol) = sscanf($volLine,"volume: %d");
if ( $this->debugging ) echo "mpd->GetVolume() / return: $vol\n";
return $vol;
/* GetPlaylist()
* Retrieves the playlist from the server and tosses it into a multidimensional array.
* NOTE: This function really should not be used. Instead, use $this->playlist. The function
* will most likely be deprecated in future releases.
function GetPlaylist() {
if ( $this->debugging ) echo "mpd->GetPlaylist()\n";
$resp = $this->SendCommand(MPD_CMD_PLLIST);
$playlist = $this->_parseFileListResponse($resp);
if ( $this->debugging ) echo "mpd->GetPlaylist() / return ".print_r($playlist)."\n";
return $playlist;
/* ----------------- Command compatibility tables --------------------- */
var $COMPATIBILITY_MIN_TBL = array(
MPD_CMD_SEEK => "0.9.1" ,
MPD_CMD_PLMOVE => "0.9.1" ,
MPD_CMD_RANDOM => "0.9.1" ,
MPD_CMD_PLSWAPTRACK => "0.9.1" ,
MPD_CMD_PLMOVETRACK => "0.9.1" ,
MPD_CMD_PASSWORD => "0.10.0" ,
MPD_CMD_SETVOL => "0.10.0"
var $COMPATIBILITY_MAX_TBL = array(
MPD_CMD_VOLUME => "0.10.0"
} // ---------------------------- end of class ------------------------------
function msort($a,$b) {
global $sort_array,$filenames_only;
$i=0;
$ret = 0;
while($filenames_only!="yes" && $i<4 && $ret==0) {
if(!isset($a[$sort_array[$i]])) {
if(isset($b[$sort_array[$i]])) {
$ret = -1;
else if(!isset($b[$sort_array[$i]])) {
$ret = 1;
else if(strcmp($sort_array[$i],"Track")==0) {
$ret = strnatcmp($a[$sort_array[$i]],$b[$sort_array[$i]]);
else {
$ret = strcasecmp($a[$sort_array[$i]],$b[$sort_array[$i]]);
$i++;
if($ret==0)
$ret = strcasecmp($a["file"],$b["file"]);
return $ret;
function picksort($pick) {
global $sort_array;
if(0==strcmp($pick,$sort_array[0])) {
return "$sort_array[0],$sort_array[1],$sort_array[2],$sort_array[3]";
else if(0==strcmp($pick,$sort_array[1])) {
return "$pick,$sort_array[0],$sort_array[2],$sort_array[3]";
else if(0==strcmp($pick,$sort_array[2])) {
return "$pick,$sort_array[0],$sort_array[1],$sort_array[3]";
else if(0==strcmp($pick,$sort_array[3])) {
return "$pick,$sort_array[0],$sort_array[1],$sort_array[2]";
?>BaconPie wrote:I used it to make a web based remote control for my phone. Glad it was of some help.
regarding the phone client, ... there is one in the phpMpReloaded project called IPodMp :-)
http://phpmpreloaded.sourceforge.net/sc … IPodMp.png
cheers
-tswaehn -
Hyperion Planning business rules migrating to Calc Manager issue
It was suggested I post this in calc manager as well, so I hope cross posting is allowed!
We are trying to migrate from Hyperion Planning 11.1.1.3 to 11.1.2.2
Our business rules were migrated to Calc Manager by our IT team. The rules run (for the most part).
Our main complaint about this migration is that it excluded our comments inside the business rules and added it's own!
When we first open the rule it is in graphical mode. But on the Script Tab I can see our orignal Business rule, but it's missing comments. Not all comments -- those at the top of the rule are intact, but after it starts getting into the meat of the rule, it loses many, but not all of the comments. When I chose to edit this rule in script mode, then calc manager adds tons if its own comments, making the code very junky to read.
So, multiple questions -- how do we get the migration of business rules to calc manager to stop losing our important comments. Is it possible to get the newly migrated rules to initially open in script mode rather than graphical mode so that it doesn't add it's own comments. Or is there a way to turn off the added commenting?
This is a snippet of our rule in 11.1.1.3:
FIX ("D0P000 Pushdown")
"Accrued Salaries and Wages Pushdown" = "BTL Accrued Sal & Wages Total"->"WBS_I19990_PLAN" * (D0P000->"Total Reg Labor" / "LMSS (LRP TEMPLATE LEVEL)"->"Total Reg Labor");
ENDFIX
/* FIX on account members that should be rolled up in the AGG statement below. */
FIX (@DESCENDANTS( "Orders"),
This is what it looks like when it comes up in graphical mode in Calc Mgr 11.1.2.2 (note that comment is already missing):
FIX ("D0P000 Pushdown")
"Accrued Salaries and Wages Pushdown" = "BTL Accrued Sal & Wages Total"->"WBS_I19990_PLAN" * (D0P000->"Total Reg Labor" / "LMSS (LRP TEMPLATE LEVEL)"->"Total Reg Labor");
ENDFIX
FIX (@DESCENDANTS( "Orders"),
This is what it looks like when it switches from graphical to script (bonus comments are added):
FIX ( /*DIM:Entities*/"D0P000 Pushdown")
/*STARTCOMPONENT:FORMULA*/
"Accrued Salaries and Wages Pushdown" = "BTL Accrued Sal & Wages Total"->"WBS_I19990_PLAN" * (D0P000->"Total Reg Labor" / "LMSS (LRP TEMPLATE LEVEL)"->"Total Reg Labor");
/*ENDCOMPONENT*/ ENDFIX
FIX ( /*DIM:Accounts*/@DESCENDANTS( "Orders"),
Thanks for any help.
BrendaYou might learn to appreciate graphical mode in Calc Manager, we do. It is not like the old Business Rules in EAS. I am an old school calc script person, and have NO love for drag-and-drop coding ... I need control. ;-)
Insert a blank script object and paste your code into the 'Script' tab for that object. Set up your prompts and use the {} notation in your code. All of the comments will stay put ... as long as you DON'T USE EDIT, SCRIPT! We make a fair number of generic, reusable pieces of code and save them as shared scripts. These can be dragged into Rules. Click on the Rule's Begin object and choose the Script tab ... you will see how the bits are assembled into complete calc script. We've even come up with a way to use LOOP ... ENDLOOP as though it were a procedural IF statement so we can control whether or not a chunk of code is active or not.
Shared scripts are especially good for currency translation components since we occasionally add new currencies and want to make a change in one object that is used in dozens of business rules.
Mike H. -
Very confused beginner here...
Hello everyone. I'm new to the board here. I am currently a junior meteorology major with a minor in computer science at Millersville University. To incorporate both my minor and major, I decided to make a computer program that scrolls weather watches and warnings across the bottom of a computer screen (much like they do on television). I am a beginner at Java, only using it for a few months. I really feel like I have bitten off more than I can chew with this program. However, I am dedicated in working through this problem. Below is a copy of the code I am using for this. I keep getting errors, however. I had it working perfectly, besides the fact that a) it never updated and b) it would never scroll more than one watch or warning, meaning it would just loop one over and over. I have also included the errors that I receive during this. Any help would be greatly appreciated. I am sorry if the code looks a bit trashy and disorganized. These are just some things, being a rookie, that I am going to have to learn how to clean up. Thanks
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.Timer;
import javax.swing.*;
import java.applet.Applet;
import java.applet.AudioClip;
import java.net.*;
import de.nava.informa.core.ChannelIF;
import de.nava.informa.core.ItemIF;
import de.nava.informa.impl.basic.ChannelBuilder;
import de.nava.informa.parsers.FeedParser;
public class WxScroll extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
int count = 0;
JLabel scrollLabel;
String scroll, watwarstring, text;
Label label;
ItemIF item;
Component newText;
String watwar[];
String newscroll, oldText;
ChannelIF channel;
Collection items;
final TimerTask task;
java.util.Timer timercheck;
ChannelBuilder channelb;
URL url;
public WxScroll() {
final Color red = new Color(255, 0, 0);
final Color yellow = new Color(255, 255, 0);
final Color orange = new Color(255, 165, 0);
final Color darkred = new Color(205, 38, 38);
final Color orangered = new Color(255, 69, 0);
final Color darkmagenta = new Color(139, 0, 139);
final Color blueviolet = new Color(138, 43, 226);
final Color lime = new Color(50, 205, 50);
final Color goldenrod = new Color(205, 155, 29);
final Color deeppink = new Color(255, 20, 147);
final Color lightsteelblue = new Color(176, 196, 222);
final Color yellowgreen = new Color(154, 205, 50);
final Color limegreen = new Color(34, 139, 34);
final Color burlywood = new Color(222, 184, 135);
final Color paleturquoise = new Color(102, 139, 139);
final Color springgreen = new Color(0, 238, 118);
final Color seagreen = new Color(46, 139, 87);
final Color greenyellow = new Color(127, 255, 0);
final Color steelblue = new Color(54, 100, 139);
final Color royalblue = new Color(65, 105, 225);
final Color hotpink = new Color(255, 105, 180);
final Color tan = new Color(205, 133, 63);
final Color skyblue = new Color(135, 206, 250);
final Color palevioletred = new Color(219, 112, 147);
final Color slateblue = new Color(0, 127, 255);
final Color coral = new Color(255, 127, 0);
final Color cornflower = new Color(100, 149, 237);
final Color maroon = new Color(176, 48, 96);
try {
URL url = new URL("file:misslebeep2.wav");
AudioClip ac = Applet.newAudioClip(url);
ac.play();
} catch (Exception e) {
timercheck = new java.util.Timer();
task = new TimerTask() {
public void run() {
try {
channel = FeedParser
.parse(
channelb = new ChannelBuilder(),
url = new URL(
"http://www.weather.gov/alerts/wwarssget.php?zone=COZ041"));
catch (Exception e) {
System.out.println("exception");
finally {
items = channel.getItems();
scrollLabel = new JLabel(newscroll);
for (Iterator i = items.iterator(); i.hasNext();) {
count++;
ItemIF item = (ItemIF) i.next();
scroll = item.getDescription();
newscroll += scroll
.replaceAll("<br>", " ")
.replaceAll(
"Issuing Weather Forecast Office Homepage",
.replaceAll("</a>", " ")
.replaceAll(
"<a href=http://www.nws.noaa.gov/er/ctp>",
if (newscroll.contains("There are no active"))
scrollLabel.setVisible(false);
else {
scrollLabel.setBackground(red);
if (newscroll.contains("Tornado warning".toUpperCase()))
scrollLabel.setBackground(red);
if (newscroll.contains("Severe thunderstorm warning"
.toUpperCase()))
scrollLabel.setBackground(orange);
if (newscroll.contains("Flash Flood Warning"
.toUpperCase()))
scrollLabel.setBackground(darkred);
if (newscroll
.contains("Blizzard Warning".toUpperCase()))
scrollLabel.setBackground(orangered);
if (newscroll.contains("ice storm warning"
.toUpperCase()))
scrollLabel.setBackground(darkmagenta);
if (newscroll.contains("short term".toUpperCase()))
scrollLabel.setBackground(burlywood);
if (newscroll.contains("heavy snow warning"
.toUpperCase()))
scrollLabel.setBackground(blueviolet);
if (newscroll.contains("heavy sleet warning"
.toUpperCase()))
scrollLabel.setBackground(skyblue);
if (newscroll.contains("flood warning".toUpperCase()))
scrollLabel.setBackground(lime);
if (newscroll.contains("high wind warning"
.toUpperCase()))
scrollLabel.setBackground(goldenrod);
if (newscroll
.contains("red flag warning".toUpperCase()))
scrollLabel.setBackground(deeppink);
if (newscroll.contains("wind chill warning"
.toUpperCase()))
scrollLabel.setBackground(lightsteelblue);
if (newscroll.contains("freeze warning".toUpperCase()))
scrollLabel.setBackground(Color.cyan);
if (newscroll.contains("snow watch".toUpperCase()))
scrollLabel.setBackground(Color.cyan);
if (newscroll.contains("flood statement".toUpperCase()))
scrollLabel.setBackground(yellowgreen);
if (newscroll.contains("tornado watch".toUpperCase()))
scrollLabel.setBackground(yellow);
if (newscroll.contains("severe thunderstorm watch"
.toUpperCase()))
scrollLabel.setBackground(palevioletred);
if (newscroll.contains("flash flood watch"
.toUpperCase()))
scrollLabel.setBackground(limegreen);
if (newscroll.contains("freezing rain".toUpperCase()))
scrollLabel.setBackground(slateblue);
if (newscroll
.contains("freezing drizzle".toUpperCase()))
scrollLabel.setBackground(slateblue);
if (newscroll.contains("sleet advisory".toUpperCase()))
scrollLabel.setBackground(slateblue);
if (newscroll.contains("winter weather advisory"
.toUpperCase()))
scrollLabel.setBackground(burlywood);
if (newscroll.contains("wind chill advisory"
.toUpperCase()))
scrollLabel.setBackground(paleturquoise);
if (newscroll.contains("heat advisory".toUpperCase()))
scrollLabel.setBackground(coral);
if (newscroll.contains("flood advisory".toUpperCase()))
scrollLabel.setBackground(springgreen);
if (newscroll.contains("snow advisory".toUpperCase()))
scrollLabel.setBackground(paleturquoise);
if (newscroll.contains("wind advisory".toUpperCase()))
scrollLabel.setBackground(tan);
if (newscroll.contains("frost advisory".toUpperCase()))
scrollLabel.setBackground(cornflower);
if (newscroll.contains("flood watch".toUpperCase()))
scrollLabel.setBackground(seagreen);
if (newscroll.contains("blizzard watch".toUpperCase()))
scrollLabel.setBackground(greenyellow);
if (newscroll.contains("winter storm watch"
.toUpperCase()))
scrollLabel.setBackground(steelblue);
if (newscroll.contains("winter storm warning"
.toUpperCase()))
scrollLabel.setBackground(hotpink);
if (newscroll.contains("high wind watch".toUpperCase()))
scrollLabel.setBackground(goldenrod);
if (newscroll.contains("excessive heat watch"
.toUpperCase()))
scrollLabel.setBackground(maroon);
if (newscroll.contains("freeze watch".toUpperCase()))
scrollLabel.setBackground(royalblue);
if (newscroll
.contains("wind chill watch".toUpperCase()))
scrollLabel.setBackground(royalblue);
if (newscroll.contains("excessive heat watch"
.toUpperCase()))
scrollLabel.setBackground(maroon);
if (newscroll.contains("excessive heat watch"
.toUpperCase()))
scrollLabel.setBackground(maroon);
if (newscroll.contains("excessive heat watch"
.toUpperCase()))
scrollLabel.setBackground(maroon);
scrollLabel.setFont(new Font("Arial", Font.BOLD, 40));
getContentPane().add(scrollLabel, BorderLayout.SOUTH);
scrollLabel.setOpaque(true);
scrollLabel.setForeground(Color.white);
// create 2nd timer. give time of 1000ms.
// event.getsource...in action performed
timercheck.scheduleAtFixedRate(task, 1000, 10000);
Timer timer = new Timer(120,this);
//javax.swing.Timer timer = new javax.swing.Timer(120, this);
timer.start();
public void actionPerformed(ActionEvent event) {
oldText = scrollLabel.getText();
StringBuffer newText = new StringBuffer(oldText.substring(1) + oldText.substring(0, 1));
String text = newText.toString();
scrollLabel = new JLabel (text);
//scrollLabel.setText(newText.toString());
public static void main(String[] args) {
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int y = (14 * screen.height) / 15;
WxScroll frame = new WxScroll();
JLabel title = new JLabel("WxScroll");
JPanel titlePanel = new JPanel();
titlePanel.setPreferredSize(new Dimension(0, 0));
titlePanel.add(title);
frame.setLocation(0, y);
// paint component method, drawstring,
frame.setUndecorated(true);
frame.setAlwaysOnTop(true);
frame.getContentPane().add(titlePanel);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}The errors i receive are:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at WxScroll.actionPerformed(WxScroll.java:289)
at javax.swing.Timer.fireActionPerformed(Unknown Source)
at javax.swing.Timer$DoPostEvent.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)I don't know. There are classes your code requires (e.g., everything in the de.nava.informa packages) that I don't have, so I can't really compile or run your code.
I will say this: it's a confused mess. There's too much code and too little abstraction. This is typical of beginning object-oriented programmers.
When you start seeing LOTS of repeated stuff like this:
if (newscroll.contains("Tornado warning".toUpperCase()))
scrollLabel.setBackground(red);
}alarm bells should start ringing in your head. It appears that a Map with a String as key and Color as value is wanted. I can make all that code collapse into something MUCH smaller. If I externalize all those awful Color declarations into a File that's read on startup (e.g., taking in the key message and the RGB values and initializing the Map), now I have something that I can change more easily. AND there's less code to manage.
I see URLs, applet, TimerTask, HTML - the kitchen sink.
I can't tell you what this class is about.
Be lazier - write less code. That's what good programmers do.
Try to think more abstractly.
% -
I wish to know if there are any refresh issues in the following scenario.
Consider the same application running in 2 distinct VM, jvm1 and jvm2 in a
simple
configuration without L2 cache.
In jvm1 I have:
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
Object oid = xxx;
Object o = pm.getObjectById(oid)
System.err.println(o.xxxx);
pm.currentTransaction().commit();
pm.close():
Then in jvm2:
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
Object oid = xxx;
Object o = pm.getObjectById(oid)
o.setSomeAttribute(xxxx);
pm.currentTransaction().commit();
pm.close():
Now if I execute in jvm1 the first code fragment, do I see the modification
applied in
jvm2 ?
Thanks in advance,
Guido Anzuoni.
BTW, are you going to include oid (and hopefully, class) keyword in
projection in kodo3 ?Guido,
Yes, you will see the modification in the next PM. The only "stale data"
issues you might see are when you get object ID X in JVM1, modify and
commit object ID X in JVM2, and then continue to reference it in JVM1
(without any closing or refreshing): you will continue to see the cached
version of object ID X.
When this situation is intolerable, you can use pessimistic
transactions: that will guarantee up-to-date views of the object, at the
cost of keeping database locks on the rows open.
In article <[email protected]>, Guido Anzuoni wrote:
No, no, just for confirmation. I have read some posts on this topic and I
have only shown my tipical usage.
Is this behaviour somehow dependent on optimistic settings ?
What if the DB schema is a preexisting one and there is no column for
optimistic locking check ?
Thanks again,
Guido.
"Stephen Kim" <[email protected]> ha scritto nel messaggio
news:[email protected]...
Yes. Are you not seeing this behavior?
As for oid and class keywords, I'm not sure if the feature has been
resolved one way or another yet.
Guido Anzuoni wrote:
I wish to know if there are any refresh issues in the following
scenario.
Consider the same application running in 2 distinct VM, jvm1 and jvm2 ina
simple
configuration without L2 cache.
In jvm1 I have:
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
Object oid = xxx;
Object o = pm.getObjectById(oid)
System.err.println(o.xxxx);
pm.currentTransaction().commit();
pm.close():
Then in jvm2:
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
Object oid = xxx;
Object o = pm.getObjectById(oid)
o.setSomeAttribute(xxxx);
pm.currentTransaction().commit();
pm.close():
Now if I execute in jvm1 the first code fragment, do I see themodification
applied in
jvm2 ?
Thanks in advance,
Guido Anzuoni.
BTW, are you going to include oid (and hopefully, class) keyword in
projection in kodo3 ?
Stephen Kim
[email protected]
SolarMetric, Inc.
http://www.solarmetric.com
Marc Prud'hommeaux [email protected]
SolarMetric Inc. http://www.solarmetric.com -
Kodo.util.UserException with deletepersistent method
Hi,
When I want to delete an object, i have the following error :
kodo.util.UserException: The given instance
"operations.offres.produits.magazines.groupesetediteurs.GroupeDePresse@6dd60e"
is not managed by this
PersistenceManager.[operations.offres.produits.magazines.groupesetediteurs.GroupeDePresse@6dd60e]
There are the persistence methods i've wrote :
* Methode de classe pour r__cuperer un groupe de presse ou un Editeur
* @param nom String
* @return GroupesEtEditeurs
public static GroupesEtEditeurs getGroupesEtEditeurs(String nom) {
Persistance p = Persistance.getPersistance();
KodoPersistenceManager pm = p.getKodoPersistenceManager();
Query requete = pm.newQuery(GroupesEtEditeurs.class);
requete.setFilter("nom == '" + nom + "'");
requete.setUnique(true);
pm.currentTransaction().begin();
Object resultat = (Object) requete.execute();
resultat = pm.detach(resultat);
pm.currentTransaction().commit();
requete.closeAll();
pm.close();
return (GroupesEtEditeurs) resultat;
* Methode de classe pour sauvegarder et mettre __ jour un Groupe de
presse ou un Editeur
* @param groupesetediteurs GroupesEtEditeurs
public static void savGroupesEtEditeurs(GroupesEtEditeurs
groupesetediteurs) {
Persistance p = Persistance.getPersistance();
KodoPersistenceManager pm = p.getKodoPersistenceManager();
pm.currentTransaction().begin();
pm.attach(groupesetediteurs);
pm.currentTransaction().commit();
pm.close();
* Methode de classe pour supprimer un Groupe de presse ou un Editeur
* @param groupesetediteurs GroupesEtEditeurs
public static void delGroupesEtEditeurs(GroupesEtEditeurs
groupesetediteurs) {
Persistance p = Persistance.getPersistance();
KodoPersistenceManager pm = p.getKodoPersistenceManager();
pm.currentTransaction().begin();
pm.deletePersistent(groupesetediteurs);
pm.currentTransaction().commit();
pm.close();
... and in the main class :
GroupeDePresse gp0 = GroupeDePresse.getGroupeDePresse("mongroupe gp3");
GroupeDePresse.savGroupeDePresse(gp0);
GroupeDePresse.delGroupeDePresse(gp0); <---- the error source !
I've no problems for query, attach / detach or update ...
Please help !
thank you,
PascalHi,
When I want to delete an object, i have the following error :
kodo.util.UserException: The given instance
"operations.offres.produits.magazines.groupesetediteurs.GroupeDePresse@6dd60e"
is not managed by this
PersistenceManager.[operations.offres.produits.magazines.groupesetediteurs.GroupeDePresse@6dd60e]
There are the persistence methods i've wrote :
* Methode de classe pour r__cuperer un groupe de presse ou un Editeur
* @param nom String
* @return GroupesEtEditeurs
public static GroupesEtEditeurs getGroupesEtEditeurs(String nom) {
Persistance p = Persistance.getPersistance();
KodoPersistenceManager pm = p.getKodoPersistenceManager();
Query requete = pm.newQuery(GroupesEtEditeurs.class);
requete.setFilter("nom == '" + nom + "'");
requete.setUnique(true);
pm.currentTransaction().begin();
Object resultat = (Object) requete.execute();
resultat = pm.detach(resultat);
pm.currentTransaction().commit();
requete.closeAll();
pm.close();
return (GroupesEtEditeurs) resultat;
* Methode de classe pour sauvegarder et mettre __ jour un Groupe de
presse ou un Editeur
* @param groupesetediteurs GroupesEtEditeurs
public static void savGroupesEtEditeurs(GroupesEtEditeurs
groupesetediteurs) {
Persistance p = Persistance.getPersistance();
KodoPersistenceManager pm = p.getKodoPersistenceManager();
pm.currentTransaction().begin();
pm.attach(groupesetediteurs);
pm.currentTransaction().commit();
pm.close();
* Methode de classe pour supprimer un Groupe de presse ou un Editeur
* @param groupesetediteurs GroupesEtEditeurs
public static void delGroupesEtEditeurs(GroupesEtEditeurs
groupesetediteurs) {
Persistance p = Persistance.getPersistance();
KodoPersistenceManager pm = p.getKodoPersistenceManager();
pm.currentTransaction().begin();
pm.deletePersistent(groupesetediteurs);
pm.currentTransaction().commit();
pm.close();
... and in the main class :
GroupeDePresse gp0 = GroupeDePresse.getGroupeDePresse("mongroupe gp3");
GroupeDePresse.savGroupeDePresse(gp0);
GroupeDePresse.delGroupeDePresse(gp0); <---- the error source !
I've no problems for query, attach / detach or update ...
Please help !
thank you,
Pascal -
Hi,
We are getting this error for the capture process:
ORA-00600: internal error code, arguments: [kdlx_logmnr_decompress : incorrect unit length passed], [16120], [6225], [0], [22044], [], [], [], [], [], [], []
OPIRIP: Uncaught error 447. Error stack:
ORA-00447: fatal error in background process
That is aborting capture queue whenever we restart. I tried by re-installing Oracle but after sometime again this issue arises.
I am new to replication thing, so don't have too much idea about this error. Following is trace file log of the error :
*** 2013-02-06 17:04:07.311
ORA-00600: internal error code, arguments: [kdlx_logmnr_decompress : incorrect unit length passed], [16120], [6225], [0], [22044], [], [], [], [], [], [], []
*** 2013-02-06 17:04:51.995
*** 2013-02-06 17:04:52.033
Begin knlcDumpCapCtx:*******************************************
Error 600 : ORA-00600: internal error code, arguments: [kdlx_logmnr_decompress : incorrect unit length passed], [16120], [6225], [0], [22044], [], [], [], [], [], [], []
Capture Name: GENEVA1$CAP : Instantiation#: 2
*** 2013-02-06 17:04:52.033
++++ Begin KNST dump for Sid: 1059 Serial#: 171
Init Time: 01/31/2013 14:55:49
++++Begin KNSTCAP dump for : GENEVA1$CAP
Capture#: 1 Logminer_Id: 1 State: CREATING LCR [ 02/06/2013 17:04:06]
Capture_Message_Number: 0x0000.045b8dd0 [73108944]
Capture_Message_Create_Time: 02/06/2013 17:04:05
Enqueue_Message_Number: 0x0000.045b8dc8 [73108936]
Enqueue_Message_Create_Time: 02/06/2013 17:04:05
Total_Messages_Captured: 4544100
Total_Messages_Created: 963971 [ 02/06/2013 17:04:06]
Total_Messages_Enqueued: 987271 [ 02/06/2013 17:04:06]
Total_Full_Evaluations: 10970
Elapsed_Capture_Time: 52593362 Elapsed_Rule_Time: 59
Elapsed_Enqueue_Time: 0 Elapsed_Lcr_Time: 1937
Elapsed_Redo_Wait_Time: 0 Elapsed_Pause_Time: 0
Apply_Name : APPLY$_GENEVA1_137
Apply_DBLink : GENEVA2
Apply_Messages_Sent: 0
++++End KNSTCAP dump
++++ End KNST DUMP
+++ Begin DBA_CAPTURE dump for: GENEVA1$CAP
Capture_Type: LOCAL
Version: 11.2.0.1.0
Source_Database: GENEVA1
Use_Database_Link: NO
Logminer_Id: 1 Logfile_Assignment: IMPLICIT
Status: ENABLED
First_Scn: 0x0000.041c5812 [68966418]
Start_Scn: 0x0000.041c5812 [68966418]
Captured_Scn: 0x0000.045b6bea [73100266]
Applied_Scn: 0x0000.045b56cd [73094861]
Last_Enqueued_Scn: 0x0000.045b8dc8 [73108936]
Capture_User: STRMADMIN
Queue: STRMADMIN.GENEVA1$CAPQ
Rule_Set_Name[+]: "STRMADMIN"."RULESET$_13"
Negative_Rule_Set_Name: "STRMADMIN"."RULESET$_38"
Checkpoint_Retention_Time: 60
+++ End DBA_CAPTURE dump
+++ Begin DBA_CAPTURE_PARAMETERS dump for: GENEVA1$CAP
PARALLELISM = 1 Set_by_User: NO
STARTUP_SECONDS = 0 Set_by_User: NO
TRACE_LEVEL = 0 Set_by_User: NO
TIME_LIMIT = -1 Set_by_User: NO
MESSAGE_LIMIT = -1 Set_by_User: NO
MAXIMUM_SCN = 0xffff.ffffffff [281474976710655] Set_by_User: NO
WRITE_ALERT_LOG = TRUE Set_by_User: NO
DISABLE_ON_LIMIT = FALSE Set_by_User: NO
DOWNSTREAM_REAL_TIME_MINE = TRUE Set_by_User: NO
MESSAGE_TRACKING_FREQUENCY = 2000000 Set_by_User: NO
SKIP_AUTOFILTERED_TABLE_DDL = TRUE Set_by_User: NO
SPLIT_THRESHOLD = 1800 Set_by_User: NO
MERGE_THRESHOLD = 60 Set_by_User: NO
+++ End DBA_CAPTURE_PARAMETERS dump
+++ Begin DBA_CAPTURE_EXTRA_ATTRIBUTES dump for: GENEVA1$CAP
+++ End DBA_CAPTURE_EXTRA_ATTRIBUTES dump
++ LogMiner Session Dump Begin::
SessionId: 1 SessionName: GENEVA1$CAP
Start SCN: 0x0000.00000000 [0]
End SCN: 0x0000.00000000 [0]
Processed SCN: 0x0000.045b94b4 [73110708]
Prepared SCN: 0x0000.045b94b4 [73110708]
Read SCN: 0x0000.045b94b6 [73110710]
Spill SCN: 0x0000.041c5812 [68966418]
Resume SCN: 0x0000.00000000 [0]
Branch SCN: 0x0000.00000000 [0]
Branch Time: 01/01/1988 00:00:00
ResetLog SCN: 0x0000.000e6c20 [945184]
ResetLog Time: 01/31/2013 12:40:10
DB ID: 1299957605 Global DB Name: GENEVA1
krvxvtm: Enabled threads: 1
Current Thread Id: 1, Thread State 0x01
Current Log Seqn: 695, Current Thrd Scn: 0x0000.045b94b6 [73110710]
Current Session State: 0x800, Current LM Compat: 0xb200000
Flags: 0x3fa802d0, Real Time Apply is On
+++ Additional Capture Information:
Capture Flags: 266245
Logminer Start SCN: 0x0000.041c5812 [68966418]
Enqueue Filter SCN: 0x0000.041c5812 [68966418]
Low SCN: 0x0000.045b8dd0 [73108944]
Capture From Date: 01/01/1988 00:00:00
Capture To Date: 01/01/1988 00:00:00
Restart Capture Flag: NO
Ping Pending: NO
Buffered Txn Count: 0
-- Xid Hash entry --
Begin knlcDumpLobHash for XID: xid: 0x000e.007.00000453
Lcr Count: 5 Flags: 82
NO LCRs BUFFERED
TAG is null
End knlcDumpXidHash
-- LOB Hash entry --
Begin knlcDumpLobHash:
Xid: Dumping Lob Hash Key-->
xid: 0x000e.007.00000453 segcol:9 intcol:0 objn:76707 objv:1 thread:1
rba: 0x0002b6.00005b29.0130 <--Done Dumping Lob Hash Key
Offset: 32241 Sequence: 5 Long_Flag: FALSE
gld2status: 213 lau boundary: FALSE
Buffered LCR dump:
Dumping lcr 0x7f415e15e0e8 : type 0
Dumping internal row LCR
(xid,scn,instnum,scnseq,flags,time,compat,compat_num)
=(0x000e.007.00000453,0x0000.045b8dc7,0,0,0x0, 02/06/2013 17:04:05,9.2.0.0.0,0)
header null flags = 0Xf7f0
gdbnm=0x7f415e15db68, GENEVA1
tag is null
UBA = 0X3.c0056b.7.18.1.12bcf
tde key id=0
Message tracking: null
Header extra: null
child_xid (null)
(lid_scn,lid_lid_scn_sqn,lcr_sqn,thread_id)=(0x0000.045b8dc7,3,1,1)
parent_xid (null)
Duration based allocation:DUR:10
(obj#,ver,opnum)=(76707,1,9)
offset = 0, size = 0, dml_id = 0, flags = 0x0
knglrowx: flags=0x0, seq#=0, thread=0, userdata=0, RBA= rba: 0x000000.00000000.0000 knglrowx: srccsetid=0, flags2=0x0
knglrowx: sys_part_nm (null)
Old column count 0
New column count 11
segcol = 1, intcol = 1, flags 0, flags3 0 knglcolx: null
allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d318
(dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
value = 10
segcol = 2, intcol = 2, flags 0, flags3 0 knglcolx: null
allocsz=51 dtytyp=1 csetform=0 ptr=0x7f415e15d2b8
(dty, kncdty, acl, csf, csi, ind)=(1,0,51,0,0,0)
value = putGetBytes8MBData_06_02_2013_17_04_619210585076288
segcol = 3, intcol = 3, flags 0, flags3 0 knglcolx: null
allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d288
(dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
value = 1
segcol = 4, intcol = 4, flags 0, flags3 0 knglcolx: null
allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d258
(dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
value = 56
segcol = 5, intcol = 5, flags 0, flags3 0 knglcolx: null
allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d228
(dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
value = 1
segcol = 6, intcol = 6, flags 0, flags3 0 knglcolx: null
allocsz=11 dtytyp=180 csetform=0 ptr=0x7f415e15d1f8
(dty, kncdty, acl, csf, csi, ind)=(180,0,11,0,0,0)
value = 2013-02-06 11:34:05.582000000
segcol = 7, intcol = 7, flags 0, flags3 0 knglcolx: null
allocsz=7 dtytyp=180 csetform=0 ptr=0x7f415e15d1c8
(dty, kncdty, acl, csf, csi, ind)=(180,0,7,0,0,0)
value = 1970-01-01 00:00:00
segcol = 8, intcol = 8, flags 0, flags3 0 knglcolx: null
allocsz=11 dtytyp=180 csetform=0 ptr=0x7f415e15d198
(dty, kncdty, acl, csf, csi, ind)=(180,0,11,0,0,0)
value = 2013-02-06 11:34:05.582000000
segcol = 9, intcol = 9, flags 1, flags3 0 knglcolx: null
allocsz=0 dtytyp=23 csetform=0 ptr=(nil)
LOB DATA
segcol = 10, intcol = 10, flags 0, flags3 0 knglcolx: null
allocsz=0 dtytyp=23 csetform=0 ptr=(nil)
value = NULL
segcol = 11, intcol = 11, flags 0, flags3 0 knglcolx: null
allocsz=2 dtytyp=2 csetform=0 ptr=0x7f415e15d168
(dty, kncdty, acl, csf, csi, ind)=(2,0,2,0,0,0)
value = 1
End knlcDumpLobHash
-- No TRIM LCR --
Unsupported Reason: Unknown
++++++++++++ Dumping Current LogMiner Lcr: +++++++++++++++
++ LCR Dump Begin: 0x15b44d160 - lob_write
op: 10, Original op: 10, baseobjn: 76707, objn: 76707, objv: 1
DF: 0x00020803, DF2: 0x00002010, MF: 0x00040000, MF2: 0x00000040
PF: 0x00000000, PF2: 0x00000000
MergeFlag: 0x03, FilterFlag: 0x09
Id: 0, iotPrimaryKeyCount: 0, numChgRec: 1
NumCrSpilled: 0
RedoThread#: 1, rba: 0x0002b6.00005ba1.017c
scn: 0x0000.045b8dd0, (scn: 0x0000.045b8dd0, scn_sqn: 5, lcr_sqn: 1)xid: 0x000e.007.00000453, parentxid: 0x000e.007.00000453, proxyxid: 0x0000.000.00000000
ncol: 11 newcount: 1, oldcount: 0
LUBA: 0x3.c0056b.7.1b.12bcf
GroupThreadId: 1, GroupRba: rba: 0x0002b6.00005b29.0130
LOB info: length: 6225, LOB offset: 0, LOB CodePoint Offset: 0
LOB ID: 0x0001000cc333
Filter Flag: KEEP
++ KRVXOA Dump Begin:
Object Number: 76707 BaseObjNum: 76707 BaseObjVersion: 1
Object Name: GENEVA_OWNER1.GNV_AST_PLD_56 Type: 2
User Cols: 11, Int Cols: 11, Kernel Cols: 11
Tab Flag: 0x40000001, Trig Flags: 0x00, OBJ$ Flags: 0x00
Property: 0x20040820, Attribute: 0x1c7f
Unsupported Columns: 0x0
End knlcDumpCapCtx:*********************************************
Please help me out to get rid of this issue.
Thanks,
HeshangHi,
To further diagnose this issue, please open a service request with oracle support. As there are related issue but they are fixed in 12C.
Thanks,
Reena Chhabra -
Can stream "capture process" skip an archivelog?
DB: 10.2.0.5, on Windows 2003 SP2 32-bits
A stream capture component in our database is stuck reading one the archive log file, and status in the v$streams_capture view is 'CREATING LCR' . It is not moving at all.
I think, the archivelog is corrupted and will guess skipping from reading the log can help??
Any idea?Find the transaction identifier in the trace file; for example in this trace the transaction is '0x000a.008.00019347'
Convert it from hex to decimal; in this example '0x000a.008.00019347' will be '10.8.103239'.
Example of trace file:
++++++++++++ Dumping Current LogMiner Lcr: +++++++++++++++
++ LCR Dump Begin: 0x000007FF3F75D8A0 - cannot_support
op: 255, Original op: 255, baseobjn: 74480, objn: 74480, objv: 1
DF: 0x00000003, DF2: 0x00000010, MF: 0x08240000, MF2: 0x00000000
PF: 0x00000000, PF2: 0x00000000
MergeFlag: 0x03, FilterFlag: 0x01
Id: 1, iotPrimaryKeyCount: 0, numChgRec: 0
NumCrSpilled: 0
RedoThread#: 1, rba: 0x000604.00014fd2.014c
scn: 0x0000.36a4b03c, (scn: 0x0000.36a4b03c, scn_sqn: 1, lcr_sqn: 0)xid: *0x000a.008.00019347*, parentxid: 0x000a.008.00019347, proxyxid: 0x0000.000.00000000, unsupportedReasonCode: 0,
ncol: 5 newcount: 0, oldcount: 0
LUBA: 0x3.c004eb.8.8.122f2
Filter Flag: UNDECIDED
++ KRVXOA Dump Begin:
Object Number: 74480 BaseObjNum: 74480 BaseObjVersion: 1
Then stop the capture process and execute the following procedure:
exec dbms_capture_adm.set_parameter('your_capture_process_name','_ignore_transaction','your_transaction_id_in_decimal_notation');
Now you can restart the capture process and it will ignore the tx. -
Importing mappings using OMBPLUS
we just started using OWB, and in our environment we do not want to migrate mappings from DEV to TEST to PRODUCTION using GUI. i heard that importing and deploying can be done using OMB scripting ..
can any please give some example scripts for importing mapping and deploying mappings on to a different box.
ThanksDo you need to move the mapping definitions over to each box? Or just deploy them to different boxes?
If you want a single design repository where you deploy from to multiple runtime areas, then this is acheived through creating multiple configurations and changing your project configuration prior to each deployment.
If, on the other hand, you want to MOVE the current mapping definitions to each box where you will, in effect, be setting up a new design AND runtime repository, then there is added complexity.
For example, scripting dropping old mappings prior to importing the new version of the project to avoid legacy objects hanging around becomes a potential issue. for that, you would need to script deployemnt plans of type DELETE for objects no longer wanted. This also helps script the new deployment as you don't have to code which mappings are being CREATEd, and which are being REPLACEd.
I have an OMB+ script I am just testing right now to load a project MDL file and deploy it to a new repository. I have a partial script for unloading and old version of the project, but it is not ready yet. This one also assumes a clean install where I even have to go so far as to register my runtime user, and define and register all schemas to be used by the control center. We also do not deploy normal database objects via OWB. This script assumes that the proper database setup for tables, sequences, views, etc. has been done prior to deploying the OWB mappings and process flows. We use Designer as the repository of record for all non-OWB database objects.
I don't claim to be an experienced TCL or OMB+ developer, but it might help you out as a starting point. Note that the config file and file of library functions used by this script (such as the exec_omb you will see that I use) are also appended to this post.
File: owb_import.tcl
#get db connection info
source c:\\omb\\owb_config.tcl
#get standard library
source c:\\omb\\omb_library.tcl
# Connect to repos
# Commit anything from previous work in this session, otherwise OMBDISCONNECT will fail out.
exec_omb OMBCOMMIT
# If already connected, disconnect first.
set print [exec_omb OMBDISCONNECT]
# Test if message is "OMB01001: Not connected to repository." or "Disconnected."
# any other message is a showstopper!
if [string match Disconn* $print ] {
log_msg LOG "Success Disconnecting from previous repository...."
} else {
# We expect an OMB01001 error for trying to disconnect when not connected
if [string match OMB01001* $print ] {
log_msg LOG "Disconnect unneccessary. Not currently connected...."
} else {
log_msg ERROR "Error Disconnecting from previous repository....Exiting process."
log_msg ERROR "$print"
#exit
set print [exec_omb OMBCONNECT $OWB_DEG_USER/$OWB_DEG_PASS@$OWB_DEG_HOST:$OWB_DEG_PORT:$OWB_DEG_SRVC USE REPOSITORY '$OWB_DEG_REPOS']
if [omb_error $print] {
log_msg ERROR "Unable to connect to repository."
log_msg ERROR "$print" "1"
log_msg ERROR "Exiting Script.............."
return
} else {
log_msg LOG "Connected to Repository"
# Connect to project
set print [exec_omb OMBCC '$PROJECT_NAME']
if [omb_error $print] {
log_msg LOG "Project $PROJECT_NAME does not exist. Creating...."
set print [exec_omb OMBCREATE PROJECT '$PROJECT_NAME']
if [omb_error $print] {
log_msg ERROR "Unable to create project '$PROJECT_NAME'"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
} else {
log_msg LOG "Created Project '$PROJECT_NAME'"
exec_omb OMBCOMMIT
exec_omb OMBSAVE
exec_omb OMBCC '$PROJECT_NAME'
} else {
log_msg LOG "Switched context to project $PROJECT_NAME"
# Check Existance of Oracle Module
set print [exec_omb OMBCC '$ORA_MODULE_NAME']
if [omb_error $print] {
log_msg LOG "Oracle Module $ORA_MODULE_NAME does not exist. Creating...."
set print [exec_omb OMBCREATE ORACLE_MODULE '$ORA_MODULE_NAME']
if [omb_error $print] {
log_msg ERROR "Unable to create module '$ORA_MODULE_NAME'"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
} else {
log_msg LOG "Created Oracle Module '$ORA_MODULE_NAME'"
exec_omb OMBCOMMIT
exec_omb OMBSAVE
exec_omb OMBCC '$ORA_MODULE_NAME'
} else {
log_msg LOG "Switched context to module $ORA_MODULE_NAME"
#switch back up to project level. You cannot attach locations to a module if you are in it.
exec_omb OMBCC '..'
log_msg LOG "Switched context back up to project $PROJECT_NAME"
# Check Existance of OWB Registered USer
set lst [OMBLIST USERS]
if {[string match *$DATA_LOCATION_USER* $lst]} {
log_msg LOG "Verify USer $DATA_LOCATION_USER Exists."
} else {
log_msg LOG "registering User $DATA_LOCATION_USER."
# set print [ exec_omb OMBREGISTER USER '$DATA_LOCATION_USER' SET PROPERTIES (DESCRIPTION, ISTARGETSCHEMA, TARGETSCHEMAPWD) VALUES ('$DATA_LOCATION_USER', 'true', '$DATA_LOCATION_PASS')]
if [omb_error $print] {
log_msg ERROR "Unable to register user '$DATA_LOCATION_USER'"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
# Import MDL File
#switch back up to root level to ensure import succeeds.
exec_omb OMBSAVE
exec_omb OMBCC '..'
log_msg LOG "Switched context back up to root level."
set print [exec_omb OMBIMPORT MDL_FILE '$IMPORT_FILE_PATH/$IMPORT_FILE_NAME' USE UPDATE_MODE MATCH_BY NAMES OUTPUT LOG TO '$IMPORT_LOG_PATH/$IMPORT_LOG_NAME' ]
if [omb_error $print] {
#We expect to get warnings due to differences in Control center names etc,
if {[string match OMB05105* $print]} {
log_msg LOG "MDL File $IMPORT_FILE_NAME imported with warnings"
} else {
log_msg ERROR "Unable to import $IMPORT_FILE_PATH/$IMPORT_FILE_NAME. "
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
} else {
log_msg LOG "MDL File $IMPORT_FILE_NAME imported with no warnings.............."
exec_omb OMBCOMMIT
exec_omb OMBCC '$PROJECT_NAME'
log_msg LOG "Switched context back to project level."
# Validate to Control Center
set lst [OMBLIST CONTROL_CENTERS]
if [string match *$CONTROL_CENTER_NAME* $lst] {
log_msg LOG "Verify Control Center $CONTROL_CENTER_NAME Exists."
log_msg LOG "Setting Passwords to enable import and deploy"
set print [exec_omb OMBALTER LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (PASSWORD) VALUES ('$DATA_LOCATION_PASS')]
if [omb_error $print] {
log_msg ERROR "Unable to log onto location '$DATA_LOCATION_NAME' with password $DATA_LOCATION_PASS"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
set print [exec_omb OMBALTER LOCATION '$WFLOW_LOCATION_NAME' SET PROPERTIES (PASSWORD) VALUES ('$WFLOW_LOCATION_PASS')]
if [omb_error $print] {
log_msg ERROR "Unable to log onto workflow location '$WFLOW_LOCATION_NAME' with password $WFLOW_LOCATION_PASS"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
log_msg LOG "Connecting to Control Center $CONTROL_CENTER_NAME"
set print [exec_omb OMBCONNECT CONTROL_CENTER USE '$DATA_LOCATION_PASS' ]
if [omb_error $print] {
log_msg ERROR "Unable to add Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
log_msg LOG "Connected.............."
} else {
log_msg LOG "Need to create Control Center $CONTROL_CENTER_NAME."
log_msg LOG "Creating Code Location."
# For Global_names = FALSE
# set print [exec_omb OMBCREATE LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (TYPE, VERSION, DESCRIPTION, BUSINESS_NAME, HOST, PORT, SERVICE, CONNECT_AS_USER, PASSWORD, DATABASE_NAME) VALUES ('ORACLE_DATABASE','$DATA_LOCATION_VERS','ERS Datamart Code User','$DATA_LOCATION_NAME', '$DATA_LOCATION_HOST','$DATA_LOCATION_PORT','$DATA_LOCATION_SRVC', '$DATA_LOCATION_USER','$DATA_LOCATION_PASS','$DATA_LOCATION_SRVC' ) ]
set print [exec_omb OMBCREATE LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (TYPE, VERSION, DESCRIPTION, BUSINESS_NAME, HOST, PORT, SERVICE, CONNECT_AS_USER, PASSWORD) VALUES ('ORACLE_DATABASE','$DATA_LOCATION_VERS','ERS Datamart Code User','$DATA_LOCATION_NAME', '$DATA_LOCATION_HOST','$DATA_LOCATION_PORT','$DATA_LOCATION_SRVC', '$DATA_LOCATION_USER','$DATA_LOCATION_PASS') ]
if [omb_error $print] {
log_msg ERROR "Unable to create location '$DATA_LOCATION_NAME'"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
log_msg LOG "Creating Workflow Location."
set print [exec_omb OMBCREATE LOCATION '$WFLOW_LOCATION_NAME' SET PROPERTIES (TYPE, VERSION, DESCRIPTION, BUSINESS_NAME, HOST, PORT, SERVICE_NAME, PASSWORD, SCHEMA) VALUES ('ORACLE_WORKFLOW','$WFLOW_LOCATION_VERS','ERS Datamart Workflow User','$WFLOW_LOCATION_NAME', '$WFLOW_LOCATION_HOST','$WFLOW_LOCATION_PORT','$WFLOW_LOCATION_SRVC', '$WFLOW_LOCATION_PASS','$WFLOW_LOCATION_USER') ]
if [omb_error $print] {
log_msg ERROR "Unable to create Workflow location '$WFLOW_LOCATION_NAME'"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
#return
exec_omb OMBCOMMIT
log_msg LOG "Creating Control Center"
set print [exec_omb OMBCREATE CONTROL_CENTER '$CONTROL_CENTER_NAME' SET PROPERTIES (DESCRIPTION, BUSINESS_NAME, HOST, PORT, SERVICE_NAME, USER, SCHEMA, PASSWORD) VALUES ('ERS Datamart Control Center','$CONTROL_CENTER_NAME', '$DATA_LOCATION_HOST','$DATA_LOCATION_PORT','$DATA_LOCATION_SRVC', '$DATA_LOCATION_USER', '$CONTROL_CENTER_SCHEMA','$DATA_LOCATION_PASS') ]
if [omb_error $print] {
log_msg ERROR "Unable to create control center '$CONTROL_CENTER_NAME'"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
log_msg LOG "Adding Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
set print [exec_omb OMBALTER CONTROL_CENTER '$CONTROL_CENTER_NAME' ADD REF LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (IS_TARGET, IS_SOURCE) VALUES ('true', 'true') ]
if [omb_error $print] {
log_msg ERROR "Unable to add Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
log_msg LOG "Adding Workflow Location $WFLOW_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
set print [exec_omb OMBALTER CONTROL_CENTER '$CONTROL_CENTER_NAME' ADD REF LOCATION '$WFLOW_LOCATION_NAME' SET PROPERTIES (IS_TARGET, IS_SOURCE) VALUES ('true', 'true') ]
if [omb_error $print] {
log_msg ERROR "Unable to add Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
#return
exec_omb OMBCOMMIT
log_msg LOG "Setting Control Center as default control center for project"
exec_omb OMBCC 'DEFAULT_CONFIGURATION'
set print [exec_omb OMBALTER DEPLOYMENT 'DEFAULT_DEPLOYMENT' SET REF CONTROL_CENTER '$CONTROL_CENTER_NAME' ]
if [omb_error $print] {
log_msg ERROR "Unable to set Control Center $CONTROL_CENTER_NAME in default configuration"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
exec_omb OMBCC '..'
log_msg LOG "Connecting to Control Center $CONTROL_CENTER_NAME"
set print [exec_omb OMBCONNECT CONTROL_CENTER USE '$DATA_LOCATION_PASS' ]
if [omb_error $print] {
log_msg ERROR "Unable to add Location $DATA_LOCATION_NAME to Control Center $CONTROL_CENTER_NAME"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
log_msg LOG "Registering Code Location."
set print [exec_omb OMBALTER LOCATION '$DATA_LOCATION_NAME' SET PROPERTIES (PASSWORD) VALUES ('$DATA_LOCATION_PASS')]
exec_omb OMBCOMMIT
set print [exec_omb OMBREGISTER LOCATION '$DATA_LOCATION_NAME']
if [omb_error $print] {
log_msg ERROR "Unable to register Location $DATA_LOCATION_NAME"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
log_msg LOG "Registering Workflow Location."
set print [exec_omb OMBALTER LOCATION '$WFLOW_LOCATION_NAME' SET PROPERTIES (PASSWORD) VALUES ('$WFLOW_LOCATION_PASS')]
exec_omb OMBCOMMIT
set print [exec_omb OMBREGISTER LOCATION '$WFLOW_LOCATION_NAME']
if [omb_error $print] {
log_msg ERROR "Unable to register Workflow Location $WFLOW_LOCATION_NAME"
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
# Assign location to Oracle Module
log_msg LOG "Assigning Code Location to Oracle Module."
set print [ exec_omb OMBALTER ORACLE_MODULE '$ORA_MODULE_NAME' ADD REFERENCE LOCATION '$DATA_LOCATION_NAME' SET AS DEFAULT ]
if [omb_error $print] {
log_msg ERROR "Unable to add reference location '$DATA_LOCATION_NAME' to module '$ORA_MODULE_NAME' "
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
set print [ exec_omb OMBALTER ORACLE_MODULE '$ORA_MODULE_NAME' SET REFERENCE METADATA_LOCATION '$DATA_LOCATION_NAME' ]
if [omb_error $print] {
log_msg ERROR "Unable to set metadata location '$DATA_LOCATION_NAME' on module '$ORA_MODULE_NAME' "
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
set print [ exec_omb OMBALTER ORACLE_MODULE '$ORA_MODULE_NAME' SET PROPERTIES (DB_LOCATION) VALUES ('$DATA_LOCATION_NAME') ]
if [omb_error $print] {
log_msg ERROR "Unable to add db_location '$DATA_LOCATION_NAME' to module '$ORA_MODULE_NAME' "
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
exec_omb OMBCOMMIT
# Assign location to Workflow Module
log_msg LOG "Assigning Location to Workflow Module."
set print [ exec_omb OMBALTER ORACLE_MODULE '$ORA_MODULE_NAME' ADD REFERENCE LOCATION '$DATA_LOCATION_NAME' SET AS DEFAULT ]
if [omb_error $print] {
log_msg ERROR "Unable to add reference location '$DATA_LOCATION_NAME' to module '$ORA_MODULE_NAME' "
log_msg ERROR "$print"
log_msg ERROR "Exiting Script.............."
exec_omb OMBROLLBACK
return
# Begin Object Deployment
log_msg LOG "*********** Deploying: Mappings ****************"
exec_omb OMBCC '$ORA_MODULE_NAME'
set mapList [ OMBLIST MAPPINGS ]
foreach mapName $mapList {
log_msg LOG "Deploying: $mapName"
set print [ exec_omb OMBCREATE TRANSIENT DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ADD ACTION 'MAPPING_DEPLOY' SET PROPERTIES (OPERATION) VALUES ('CREATE') SET REFERENCE MAPPING '$mapName' ]
if [omb_error $print] {
log_msg ERROR "Unable to create Deployment plan for '$mapName'"
log_msg ERROR "$print"
return
set print [ exec_omb OMBDEPLOY DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ]
if [omb_error $print] {
log_msg ERROR "Error on execute of Deployment plan for '$mapName'"
log_msg ERROR "$print"
exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN'
exec_omb OMBCOMMIT
return
exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN'
exec_omb OMBCOMMIT
log_msg LOG "*********** Deploying: Process Flows **************"
exec_omb OMBCC '..'
exec_omb OMBCC '..'
set all_Owfs [OMBLIST PROCESS_FLOW_PACKAGES]
if {$all_Owfs!="" } {
foreach one_Owf $all_Owfs {
set print [ exec_omb OMBCREATE TRANSIENT DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ]
if [omb_error $print] {
log_msg ERROR "Unable to create Deployment plan for '$one_Owf'"
log_msg ERROR "$print"
return
set print [ exec_omb OMBALTER DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ADD ACTION 'OWFDEP$one_Owf' SET PROPERTIES (OPERATION) VALUES ('CREATE') SET REFERENCE PROCESS_FLOW_PACKAGE '$one_Owf' ]
if [omb_error $print] {
log_msg ERROR "Unable to alter Deployment plan for '$one_Owf'"
log_msg ERROR "$print"
exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN'
return
log_msg LOG "OWF LOCATION: $Process_Flow_Module - OWF: $one_Owf Deployment...";
set print [ exec_omb OMBDEPLOY DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ]
if [omb_error $print] {
log_msg ERROR "Unable to execute Deployment plan for '$one_Owf'"
log_msg ERROR "$print"
exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN'
return
set print [ exec_omb OMBDROP DEPLOYMENT_ACTION_PLAN 'DEPLOY_PLAN' ]
log_msg LOG "OWF LOCATION: $Process_Flow_Module - OWF: $one_Owf Deployed";
log_msg LOG "OWF LOCATION: $Process_Flow_Module - All Workflows Deployed...";
#OMBDISCONNECTWhich depends on the following two files:
OMB_LIBRARY.TCL
# Default logging function.
# Accepts inputs: LOGMSG - a text string to output
# FORCELOG - if "1" then output regardless of VERBOSE_LOG setting
proc log_msg {LOGTYPE LOGMSG {FORCELOG "0"}} {
global VERBOSE_LOG
if { $VERBOSE_LOG == "1"} {
puts "$LOGTYPE:-> $LOGMSG"
} else {
if { $FORCELOG == "1"} {
puts "$LOGTYPE:-> $LOGMSG"
proc exec_omb { args } {
log_msg OMBCMD "$args"
# the point of this is simply to return errorMsg or return string, whichever is applicable,
# to simplify error checking using omb_error{}
if [catch { set retstr [eval $args] } errmsg] {
return $errmsg
} else {
return $retstr
proc omb_error { retstr } {
# OMB and Oracle errors may have caused a failure.
if [string match OMB0* $retstr] {
return 1
} elseif [string match ORA-* $retstr] {
return 1
} else {
return 0
}and a config file where all config/passowrd info is put.
# GLOBAL VARIABLE DECLARATION SECTION
#DESIGN REPOSITORY CONNECTION INFORMATION
# Login info for the main design repository owner
set OWB_DEG_USER owb_user
set OWB_DEG_PASS password
set OWB_DEG_HOST host01
set OWB_DEG_PORT 5555
set OWB_DEG_SRVC orcl_srvc
set OWB_DEG_REPOS owb_user
# CONTROL CENTER AND LOCATION DECLARATION SECTION
set CONTROL_CENTER_NAME ERS_DM_CTLCNTR
set CONTROL_CENTER_SCHEMA owb_user
#Connection info to ers_etl_app schema for deployment
set DATA_LOCATION_NAME ERS_DM_DATA
set DATA_LOCATION_VERS 9.2
set DATA_LOCATION_USER ERS_ETL_APP
set DATA_LOCATION_PASS ers_etl_app
set DATA_LOCATION_HOST newserver
set DATA_LOCATION_PORT 1555
set DATA_LOCATION_SRVC orcl_new
#Connection info to workflow schema for deployment
set WFLOW_LOCATION_NAME ERS_DM_WFLOW
set WFLOW_LOCATION_VERS 2.6.2
set WFLOW_LOCATION_USER OWF_MGR
set WFLOW_LOCATION_PASS owf_mgr
set WFLOW_LOCATION_HOST newserver
set WFLOW_LOCATION_PORT 1555
set WFLOW_LOCATION_SRVC orcl_new
# PROJECT,MUDULE AND DIRECTORY DECLARATION SECTION
set PROJECT_NAME ERS_DM
set ORA_MODULE_NAME ERS_ETL_APP
set PFLOW_MODULE_NAME LD_DMRT
set PFLOW_PACKAGE_NAME LD_DMRT
# Directory DECLARATION SECTION
set IMPORT_FILE_NAME "ers_dply_tst_rc01.mdl"
set IMPORT_FILE_PATH "C:/OMB/import/db_imports"
set IMPORT_LOG_NAME "ers_dply_tst_rc01_imp.log"
set IMPORT_LOG_PATH "C:/OMB/import/logs"
# Logging Option
global VERBOSE_LOG
set VERBOSE_LOG "1"Hope that this helps you out!
Message was edited by: zeppo
Edited to: Try and correct formatting tags. -
I'm half way through writing a web interface for mpd. I needed a way to interact with it so I searched around and found this. It's a php class that interfaces with mpd.
I downloaded it and it comes with an example php file for using it. The only problem is that when I use the example page it just prints out anything after the arrow operator. As far as I'm aware the arrow operator is for accessing class methods and variables but I've never actually done any OOP with PHP.
Anyway here is the example file:
<?
* mpd-class-example.php - Example interface using mpd.class.php
* Version 1.2, released 05/05/2004
* Copyright (C) 2003-2004 Benjamin Carlisle ([email protected])
* http://mpd.24oz.com/ | http://www.musicpd.org/
* This program illustrates the basic commands and usage of the MPD class.
* *** PLEASE NOTE *** My intention in including this file is not to provide you with an
* out-of-the-box MPD jukebox, but instead to provide a general understanding of how I saw
* the class as being utilized. If you'd like to see more examples, please let me know. But
* this should provide you with a good starting point for your own program development.
* 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
?>
<HTML>
<style type="text/css"><!-- .defaultText { font-family: Arial, Helvetica, sans-serif; font-size: 9pt; font-style: normal; font-weight: normal; color: #111111} .err { color: #DD3333 } --></style>
<BODY class="defaultText">
<?
include('mpd.class.php');
$myMpd = new mpd('localhost',2100);
if ( $myMpd->connected == FALSE ) {
echo "Error Connecting: " . $myMpd->errStr;
} else {
switch ($_REQUEST[m]) {
case "add":
if ( is_null($myMpd->PLAdd($_REQUEST[filename])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "rem":
if ( is_null($myMpd->PLRemove($_REQUEST[id])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "setvol":
if ( is_null($myMpd->SetVolume($_REQUEST[vol])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "play":
if ( is_null($myMpd->Play()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "stop":
if ( is_null($myMpd->Stop()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "pause":
if ( is_null($myMpd->Pause()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
default:
break;
?>
<DIV ALIGN=CENTER>[ <A HREF="<? echo $_SERVER[PHP_SELF] ?>">Refresh Page</A> ]</DIV>
<HR>
<B>Connected to MPD Version <? echo $myMpd->mpd_version ?> at <? echo $myMpd->host ?>:<? echo $myMpd->port ?></B><BR>
State:
<?
switch ($myMpd->state) {
case MPD_STATE_PLAYING: echo "MPD is Playing [<A HREF='".$_SERVER[PHP_SELF]."?m=pause'>Pause</A>] [<A HREF='".$_SERVER[PHP_SELF]."?m=stop'>Stop</A>]"; break;
case MPD_STATE_PAUSED: echo "MPD is Paused [<A HREF='".$_SERVER[PHP_SELF]."?m=pause'>Unpause</A>]"; break;
case MPD_STATE_STOPPED: echo "MPD is Stopped [<A HREF='".$_SERVER[PHP_SELF]."?m=play'>Play</A>]"; break;
default: echo "(Unknown State!)"; break;
?>
<BR>
Volume: <? echo $myMpd->volume ?> [ <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=0'>0</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=25'>25</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=75'>75</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=100'>100</A> ]<BR>
Uptime: <? echo secToTimeStr($myMpd->uptime) ?><BR>
Playtime: <? echo secToTimeStr($myMpd->playtime) ?><BR>
<? if ( $myMpd->state == MPD_STATE_PLAYING or $myMpd->state == MPD_STATE_PAUSED ) { ?>
Currently Playing: <? echo $myMpd->playlist[$myMpd->current_track_id]['Artist']." - ".$myMpd->playlist[$myMpd->current_track_id]['Title'] ?><BR>
Track Position: <? echo $myMpd->current_track_position."/".$myMpd->current_track_length." (".(round(($myMpd->current_track_position/$myMpd->current_track_length),2)*100)."%)" ?><BR>
Playlist Position: <? echo ($myMpd->current_track_id+1)."/".$myMpd->playlist_count." (".(round((($myMpd->current_track_id+1)/$myMpd->playlist_count),2)*100)."%)" ?><BR>
<? } ?>
<HR>
<B>Playlist - Total: <? echo $myMpd->playlist_count ?> tracks (Click to Remove)</B><BR>
<?
if ( is_null($myMpd->playlist) ) echo "ERROR: " .$myMpd->errStr."\n";
else {
foreach ($myMpd->playlist as $id => $entry) {
echo ( $id == $myMpd->current_track_id ? "<B>" : "" ) . ($id+1) . ". <A HREF='".$_SERVER[PHP_SELF]."?m=rem&id=".$id."'>".$entry['Artist']." - ".$entry['Title']."</A>".( $id == $myMpd->current_track_id ? "</B>" : "" )."<BR>\n";
?>
<HR>
<B>Sample Search for the String 'U2' (Click to Add to Playlist)</B><BR>
<?
$sl = $myMpd->Search(MPD_SEARCH_ARTIST,'U2');
if ( is_null($sl) ) echo "ERROR: " .$myMpd->errStr."\n";
else {
foreach ($sl as $id => $entry) {
echo ($id+1) . ": <A HREF='".$_SERVER[PHP_SELF]."?m=add&filename=".urlencode($entry['file'])."'>".$entry['Artist']." - ".$entry['Title']."</A><BR>\n";
if ( count($sl) == 0 ) echo "<I>No results returned from search.</I>";
// Example of how you would use Bulk Add features of MPD
// $myarray = array();
// $myarray[0] = "ACDC - Thunderstruck.mp3";
// $myarray[1] = "ACDC - Back In Black.mp3";
// $myarray[2] = "ACDC - Hells Bells.mp3";
// if ( is_null($myMpd->PLAddBulk($myarray)) ) echo "ERROR: ".$myMpd->errStr."\n";
?>
<HR>
<B>Artist List</B><BR>
<?
if ( is_null($ar = $myMpd->GetArtists()) ) echo "ERROR: " .$myMpd->errStr."\n";
else {
while(list($key, $value) = each($ar) ) {
echo ($key+1) . ". " . $value . "<BR>";
$myMpd->Disconnect();
// Used to make number of seconds perty.
function secToTimeStr($secs) {
$days = ($secs%604800)/86400;
$hours = (($secs%604800)%86400)/3600;
$minutes = ((($secs%604800)%86400)%3600)/60;
$seconds = (((($secs%604800)%86400)%3600)%60);
if (round($days)) $timestring .= round($days)."d ";
if (round($hours)) $timestring .= round($hours)."h ";
if (round($minutes)) $timestring .= round($minutes)."m";
if (!round($minutes)&&!round($hours)&&!round($days)) $timestring.=" ".round($seconds)."s";
return $timestring;
?>
</BODY></HTML>
The class file:
<?php
* mpd.class.php - PHP Object Interface to the MPD Music Player Daemon
* Version 1.2, Released 05/05/2004
* Copyright (C) 2003-2004 Benjamin Carlisle ([email protected])
* http://mpd.24oz.com/ | http://www.musicpd.org/
* 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
// Create common command definitions for MPD to use
define("MPD_CMD_STATUS", "status");
define("MPD_CMD_STATISTICS", "stats");
define("MPD_CMD_VOLUME", "volume");
define("MPD_CMD_SETVOL", "setvol");
define("MPD_CMD_PLAY", "play");
define("MPD_CMD_STOP", "stop");
define("MPD_CMD_PAUSE", "pause");
define("MPD_CMD_NEXT", "next");
define("MPD_CMD_PREV", "previous");
define("MPD_CMD_PLLIST", "playlistinfo");
define("MPD_CMD_PLADD", "add");
define("MPD_CMD_PLREMOVE", "delete");
define("MPD_CMD_PLCLEAR", "clear");
define("MPD_CMD_PLSHUFFLE", "shuffle");
define("MPD_CMD_PLLOAD", "load");
define("MPD_CMD_PLSAVE", "save");
define("MPD_CMD_KILL", "kill");
define("MPD_CMD_REFRESH", "update");
define("MPD_CMD_REPEAT", "repeat");
define("MPD_CMD_LSDIR", "lsinfo");
define("MPD_CMD_SEARCH", "search");
define("MPD_CMD_START_BULK", "command_list_begin");
define("MPD_CMD_END_BULK", "command_list_end");
define("MPD_CMD_FIND", "find");
define("MPD_CMD_RANDOM", "random");
define("MPD_CMD_SEEK", "seek");
define("MPD_CMD_PLSWAPTRACK", "swap");
define("MPD_CMD_PLMOVETRACK", "move");
define("MPD_CMD_PASSWORD", "password");
define("MPD_CMD_TABLE", "list");
// Predefined MPD Response messages
define("MPD_RESPONSE_ERR", "ACK");
define("MPD_RESPONSE_OK", "OK");
// MPD State Constants
define("MPD_STATE_PLAYING", "play");
define("MPD_STATE_STOPPED", "stop");
define("MPD_STATE_PAUSED", "pause");
// MPD Searching Constants
define("MPD_SEARCH_ARTIST", "artist");
define("MPD_SEARCH_TITLE", "title");
define("MPD_SEARCH_ALBUM", "album");
// MPD Cache Tables
define("MPD_TBL_ARTIST","artist");
define("MPD_TBL_ALBUM","album");
class mpd {
// TCP/Connection variables
var $host;
var $port;
var $password;
var $mpd_sock = NULL;
var $connected = FALSE;
// MPD Status variables
var $mpd_version = "(unknown)";
var $state;
var $current_track_position;
var $current_track_length;
var $current_track_id;
var $volume;
var $repeat;
var $random;
var $uptime;
var $playtime;
var $db_last_refreshed;
var $num_songs_played;
var $playlist_count;
var $num_artists;
var $num_albums;
var $num_songs;
var $playlist = array();
// Misc Other Vars
var $mpd_class_version = "1.2";
var $debugging = FALSE; // Set to TRUE to turn extended debugging on.
var $errStr = ""; // Used for maintaining information about the last error message
var $command_queue; // The list of commands for bulk command sending
// =================== BEGIN OBJECT METHODS ================
/* mpd() : Constructor
* Builds the MPD object, connects to the server, and refreshes all local object properties.
function mpd($srv,$port,$pwd = NULL) {
$this->host = $srv;
$this->port = $port;
$this->password = $pwd;
$resp = $this->Connect();
if ( is_null($resp) ) {
$this->errStr = "Could not connect";
return;
} else {
list ( $this->mpd_version ) = sscanf($resp, MPD_RESPONSE_OK . " MPD %s\n");
if ( ! is_null($pwd) ) {
if ( is_null($this->SendCommand(MPD_CMD_PASSWORD,$pwd)) ) {
$this->connected = FALSE;
return; // bad password or command
if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!
$this->connected = FALSE;
$this->errStr = "Password supplied does not have read access";
return;
} else {
if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected!
$this->connected = FALSE;
$this->errStr = "Password required to access server";
return;
/* Connect()
* Connects to the MPD server.
* NOTE: This is called automatically upon object instantiation; you should not need to call this directly.
function Connect() {
if ( $this->debugging ) echo "mpd->Connect() / host: ".$this->host.", port: ".$this->port."\n";
$this->mpd_sock = fsockopen($this->host,$this->port,$errNo,$errStr,10);
if (!$this->mpd_sock) {
$this->errStr = "Socket Error: $errStr ($errNo)";
return NULL;
} else {
while(!feof($this->mpd_sock)) {
$response = fgets($this->mpd_sock,1024);
if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {
$this->connected = TRUE;
return $response;
break;
if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {
$this->errStr = "Server responded with: $response";
return NULL;
// Generic response
$this->errStr = "Connection not available";
return NULL;
/* SendCommand()
* Sends a generic command to the MPD server. Several command constants are pre-defined for
* use (see MPD_CMD_* constant definitions above).
function SendCommand($cmdStr,$arg1 = "",$arg2 = "") {
if ( $this->debugging ) echo "mpd->SendCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";
if ( ! $this->connected ) {
echo "mpd->SendCommand() / Error: Not connected\n";
} else {
// Clear out the error String
$this->errStr = "";
$respStr = "";
// Check the command compatibility:
if ( ! $this->_checkCompatibility($cmdStr) ) {
return NULL;
if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";
if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";
fputs($this->mpd_sock,"$cmdStr\n");
while(!feof($this->mpd_sock)) {
$response = fgets($this->mpd_sock,1024);
// An OK signals the end of transmission -- we'll ignore it
if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) {
break;
// An ERR signals the end of transmission with an error! Let's grab the single-line message.
if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) {
list ( $junk, $errTmp ) = split(MPD_RESPONSE_ERR . " ",$response );
$this->errStr = strtok($errTmp,"\n");
if ( strlen($this->errStr) > 0 ) {
return NULL;
// Build the response string
$respStr .= $response;
if ( $this->debugging ) echo "mpd->SendCommand() / response: '".$respStr."'\n";
return $respStr;
/* QueueCommand()
* Queues a generic command for later sending to the MPD server. The CommandQueue can hold
* as many commands as needed, and are sent all at once, in the order they are queued, using
* the SendCommandQueue() method. The syntax for queueing commands is identical to SendCommand().
function QueueCommand($cmdStr,$arg1 = "",$arg2 = "") {
if ( $this->debugging ) echo "mpd->QueueCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n";
if ( ! $this->connected ) {
echo "mpd->QueueCommand() / Error: Not connected\n";
return NULL;
} else {
if ( strlen($this->command_queue) == 0 ) {
$this->command_queue = MPD_CMD_START_BULK . "\n";
if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\"";
if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\"";
$this->command_queue .= $cmdStr ."\n";
if ( $this->debugging ) echo "mpd->QueueCommand() / return\n";
return TRUE;
/* SendCommandQueue()
* Sends all commands in the Command Queue to the MPD server. See also QueueCommand().
function SendCommandQueue() {
if ( $this->debugging ) echo "mpd->SendCommandQueue()\n";
if ( ! $this->connected ) {
echo "mpd->SendCommandQueue() / Error: Not connected\n";
return NULL;
} else {
$this->command_queue .= MPD_CMD_END_BULK . "\n";
if ( is_null($respStr = $this->SendCommand($this->command_queue)) ) {
return NULL;
} else {
$this->command_queue = NULL;
if ( $this->debugging ) echo "mpd->SendCommandQueue() / response: '".$respStr."'\n";
return $respStr;
/* AdjustVolume()
* Adjusts the mixer volume on the MPD by <modifier>, which can be a positive (volume increase),
* or negative (volume decrease) value.
function AdjustVolume($modifier) {
if ( $this->debugging ) echo "mpd->AdjustVolume()\n";
if ( ! is_numeric($modifier) ) {
$this->errStr = "AdjustVolume() : argument 1 must be a numeric value";
return NULL;
$this->RefreshInfo();
$newVol = $this->volume + $modifier;
$ret = $this->SetVolume($newVol);
if ( $this->debugging ) echo "mpd->AdjustVolume() / return\n";
return $ret;
/* SetVolume()
* Sets the mixer volume to <newVol>, which should be between 1 - 100.
function SetVolume($newVol) {
if ( $this->debugging ) echo "mpd->SetVolume()\n";
if ( ! is_numeric($newVol) ) {
$this->errStr = "SetVolume() : argument 1 must be a numeric value";
return NULL;
// Forcibly prevent out of range errors
if ( $newVol < 0 ) $newVol = 0;
if ( $newVol > 100 ) $newVol = 100;
// If we're not compatible with SETVOL, we'll try adjusting using VOLUME
if ( $this->_checkCompatibility(MPD_CMD_SETVOL) ) {
if ( ! is_null($ret = $this->SendCommand(MPD_CMD_SETVOL,$newVol))) $this->volume = $newVol;
} else {
$this->RefreshInfo(); // Get the latest volume
if ( is_null($this->volume) ) {
return NULL;
} else {
$modifier = ( $newVol - $this->volume );
if ( ! is_null($ret = $this->SendCommand(MPD_CMD_VOLUME,$modifier))) $this->volume = $newVol;
if ( $this->debugging ) echo "mpd->SetVolume() / return\n";
return $ret;
/* GetDir()
* Retrieves a database directory listing of the <dir> directory and places the results into
* a multidimensional array. If no directory is specified, the directory listing is at the
* base of the MPD music path.
function GetDir($dir = "") {
if ( $this->debugging ) echo "mpd->GetDir()\n";
$resp = $this->SendCommand(MPD_CMD_LSDIR,$dir);
$dirlist = $this->_parseFileListResponse($resp);
if ( $this->debugging ) echo "mpd->GetDir() / return ".print_r($dirlist)."\n";
return $dirlist;
/* PLAdd()
* Adds each track listed in a single-dimensional <trackArray>, which contains filenames
* of tracks to add, to the end of the playlist. This is used to add many, many tracks to
* the playlist in one swoop.
function PLAddBulk($trackArray) {
if ( $this->debugging ) echo "mpd->PLAddBulk()\n";
$num_files = count($trackArray);
for ( $i = 0; $i < $num_files; $i++ ) {
$this->QueueCommand(MPD_CMD_PLADD,$trackArray[$i]);
$resp = $this->SendCommandQueue();
$this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLAddBulk() / return\n";
return $resp;
/* PLAdd()
* Adds the file <file> to the end of the playlist. <file> must be a track in the MPD database.
function PLAdd($fileName) {
if ( $this->debugging ) echo "mpd->PLAdd()\n";
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,$fileName))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLAdd() / return\n";
return $resp;
/* PLMoveTrack()
* Moves track number <origPos> to position <newPos> in the playlist. This is used to reorder
* the songs in the playlist.
function PLMoveTrack($origPos, $newPos) {
if ( $this->debugging ) echo "mpd->PLMoveTrack()\n";
if ( ! is_numeric($origPos) ) {
$this->errStr = "PLMoveTrack(): argument 1 must be numeric";
return NULL;
if ( $origPos < 0 or $origPos > $this->playlist_count ) {
$this->errStr = "PLMoveTrack(): argument 1 out of range";
return NULL;
if ( $newPos < 0 ) $newPos = 0;
if ( $newPos > $this->playlist_count ) $newPos = $this->playlist_count;
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$origPos,$newPos))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLMoveTrack() / return\n";
return $resp;
/* PLShuffle()
* Randomly reorders the songs in the playlist.
function PLShuffle() {
if ( $this->debugging ) echo "mpd->PLShuffle()\n";
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLSHUFFLE))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLShuffle() / return\n";
return $resp;
/* PLLoad()
* Retrieves the playlist from <file>.m3u and loads it into the current playlist.
function PLLoad($file) {
if ( $this->debugging ) echo "mpd->PLLoad()\n";
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLLOAD,$file))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLLoad() / return\n";
return $resp;
/* PLSave()
* Saves the playlist to <file>.m3u for later retrieval. The file is saved in the MPD playlist
* directory.
function PLSave($file) {
if ( $this->debugging ) echo "mpd->PLSave()\n";
$resp = $this->SendCommand(MPD_CMD_PLSAVE,$file);
if ( $this->debugging ) echo "mpd->PLSave() / return\n";
return $resp;
/* PLClear()
* Empties the playlist.
function PLClear() {
if ( $this->debugging ) echo "mpd->PLClear()\n";
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLCLEAR))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLClear() / return\n";
return $resp;
/* PLRemove()
* Removes track <id> from the playlist.
function PLRemove($id) {
if ( $this->debugging ) echo "mpd->PLRemove()\n";
if ( ! is_numeric($id) ) {
$this->errStr = "PLRemove() : argument 1 must be a numeric value";
return NULL;
if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLREMOVE,$id))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->PLRemove() / return\n";
return $resp;
/* SetRepeat()
* Enables 'loop' mode -- tells MPD continually loop the playlist. The <repVal> parameter
* is either 1 (on) or 0 (off).
function SetRepeat($repVal) {
if ( $this->debugging ) echo "mpd->SetRepeat()\n";
$rpt = $this->SendCommand(MPD_CMD_REPEAT,$repVal);
$this->repeat = $repVal;
if ( $this->debugging ) echo "mpd->SetRepeat() / return\n";
return $rpt;
/* SetRandom()
* Enables 'randomize' mode -- tells MPD to play songs in the playlist in random order. The
* <rndVal> parameter is either 1 (on) or 0 (off).
function SetRandom($rndVal) {
if ( $this->debugging ) echo "mpd->SetRandom()\n";
$resp = $this->SendCommand(MPD_CMD_RANDOM,$rndVal);
$this->random = $rndVal;
if ( $this->debugging ) echo "mpd->SetRandom() / return\n";
return $resp;
/* Shutdown()
* Shuts down the MPD server (aka sends the KILL command). This closes the current connection,
* and prevents future communication with the server.
function Shutdown() {
if ( $this->debugging ) echo "mpd->Shutdown()\n";
$resp = $this->SendCommand(MPD_CMD_SHUTDOWN);
$this->connected = FALSE;
unset($this->mpd_version);
unset($this->errStr);
unset($this->mpd_sock);
if ( $this->debugging ) echo "mpd->Shutdown() / return\n";
return $resp;
/* DBRefresh()
* Tells MPD to rescan the music directory for new tracks, and to refresh the Database. Tracks
* cannot be played unless they are in the MPD database.
function DBRefresh() {
if ( $this->debugging ) echo "mpd->DBRefresh()\n";
$resp = $this->SendCommand(MPD_CMD_REFRESH);
// Update local variables
$this->RefreshInfo();
if ( $this->debugging ) echo "mpd->DBRefresh() / return\n";
return $resp;
/* Play()
* Begins playing the songs in the MPD playlist.
function Play() {
if ( $this->debugging ) echo "mpd->Play()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY) )) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Play() / return\n";
return $rpt;
/* Stop()
* Stops playing the MPD.
function Stop() {
if ( $this->debugging ) echo "mpd->Stop()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_STOP) )) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Stop() / return\n";
return $rpt;
/* Pause()
* Toggles pausing on the MPD. Calling it once will pause the player, calling it again
* will unpause.
function Pause() {
if ( $this->debugging ) echo "mpd->Pause()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PAUSE) )) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Pause() / return\n";
return $rpt;
/* SeekTo()
* Skips directly to the <idx> song in the MPD playlist.
function SkipTo($idx) {
if ( $this->debugging ) echo "mpd->SkipTo()\n";
if ( ! is_numeric($idx) ) {
$this->errStr = "SkipTo() : argument 1 must be a numeric value";
return NULL;
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY,$idx))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->SkipTo() / return\n";
return $idx;
/* SeekTo()
* Skips directly to a given position within a track in the MPD playlist. The <pos> argument,
* given in seconds, is the track position to locate. The <track> argument, if supplied is
* the track number in the playlist. If <track> is not specified, the current track is assumed.
function SeekTo($pos, $track = -1) {
if ( $this->debugging ) echo "mpd->SeekTo()\n";
if ( ! is_numeric($pos) ) {
$this->errStr = "SeekTo() : argument 1 must be a numeric value";
return NULL;
if ( ! is_numeric($track) ) {
$this->errStr = "SeekTo() : argument 2 must be a numeric value";
return NULL;
if ( $track == -1 ) {
$track = $this->current_track_id;
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_SEEK,$track,$pos))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->SeekTo() / return\n";
return $pos;
/* Next()
* Skips to the next song in the MPD playlist. If not playing, returns an error.
function Next() {
if ( $this->debugging ) echo "mpd->Next()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_NEXT))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Next() / return\n";
return $rpt;
/* Previous()
* Skips to the previous song in the MPD playlist. If not playing, returns an error.
function Previous() {
if ( $this->debugging ) echo "mpd->Previous()\n";
if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PREV))) $this->RefreshInfo();
if ( $this->debugging ) echo "mpd->Previous() / return\n";
return $rpt;
/* Search()
* Searches the MPD database. The search <type> should be one of the following:
* MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM
* The search <string> is a case-insensitive locator string. Anything that contains
* <string> will be returned in the results.
function Search($type,$string) {
if ( $this->debugging ) echo "mpd->Search()\n";
if ( $type != MPD_SEARCH_ARTIST and
$type != MPD_SEARCH_ALBUM and
$type != MPD_SEARCH_TITLE ) {
$this->errStr = "mpd->Search(): invalid search type";
return NULL;
} else {
if ( is_null($resp = $this->SendCommand(MPD_CMD_SEARCH,$type,$string))) return NULL;
$searchlist = $this->_parseFileListResponse($resp);
if ( $this->debugging ) echo "mpd->Search() / return ".print_r($searchlist)."\n";
return $searchlist;
/* Find()
* Find() looks for exact matches in the MPD database. The find <type> should be one of
* the following:
* MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM
* The find <string> is a case-insensitive locator string. Anything that exactly matches
* <string> will be returned in the results.
function Find($type,$string) {
if ( $this->debugging ) echo "mpd->Find()\n";
if ( $type != MPD_SEARCH_ARTIST and
$type != MPD_SEARCH_ALBUM and
$type != MPD_SEARCH_TITLE ) {
$this->errStr = "mpd->Find(): invalid find type";
return NULL;
} else {
if ( is_null($resp = $this->SendCommand(MPD_CMD_FIND,$type,$string))) return NULL;
$searchlist = $this->_parseFileListResponse($resp);
if ( $this->debugging ) echo "mpd->Find() / return ".print_r($searchlist)."\n";
return $searchlist;
/* Disconnect()
* Closes the connection to the MPD server.
function Disconnect() {
if ( $this->debugging ) echo "mpd->Disconnect()\n";
fclose($this->mpd_sock);
$this->connected = FALSE;
unset($this->mpd_version);
unset($this->errStr);
unset($this->mpd_sock);
/* GetArtists()
* Returns the list of artists in the database in an associative array.
function GetArtists() {
if ( $this->debugging ) echo "mpd->GetArtists()\n";
if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ARTIST))) return NULL;
$arArray = array();
$arLine = strtok($resp,"\n");
$arName = "";
$arCounter = -1;
while ( $arLine ) {
list ( $element, $value ) = split(": ",$arLine);
if ( $element == "Artist" ) {
$arCounter++;
$arName = $value;
$arArray[$arCounter] = $arName;
$arLine = strtok("\n");
if ( $this->debugging ) echo "mpd->GetArtists()\n";
return $arArray;
/* GetAlbums()
* Returns the list of albums in the database in an associative array. Optional parameter
* is an artist Name which will list all albums by a particular artist.
function GetAlbums( $ar = NULL) {
if ( $this->debugging ) echo "mpd->GetAlbums()\n";
if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ALBUM, $ar ))) return NULL;
$alArray = array();
$alLine = strtok($resp,"\n");
$alName = "";
$alCounter = -1;
while ( $alLine ) {
list ( $element, $value ) = split(": ",$alLine);
if ( $element == "Album" ) {
$alCounter++;
$alName = $value;
$alArray[$alCounter] = $alName;
$alLine = strtok("\n");
if ( $this->debugging ) echo "mpd->GetAlbums()\n";
return $alArray;
//***************************** INTERNAL FUNCTIONS ******************************//
/* _computeVersionValue()
* Computes a compatibility value from a version string
function _computeVersionValue($verStr) {
list ($ver_maj, $ver_min, $ver_rel ) = split("\.",$verStr);
return ( 100 * $ver_maj ) + ( 10 * $ver_min ) + ( $ver_rel );
/* _checkCompatibility()
* Check MPD command compatibility against our internal table. If there is no version
* listed in the table, allow it by default.
function _checkCompatibility($cmd) {
// Check minimum compatibility
$req_ver_low = $this->COMPATIBILITY_MIN_TBL[$cmd];
$req_ver_hi = $this->COMPATIBILITY_MAX_TBL[$cmd];
$mpd_ver = $this->_computeVersionValue($this->mpd_version);
if ( $req_ver_low ) {
$req_ver = $this->_computeVersionValue($req_ver_low);
if ( $mpd_ver < $req_ver ) {
$this->errStr = "Command '$cmd' is not compatible with this version of MPD, version ".$req_ver_low." required";
return FALSE;
// Check maxmum compatibility -- this will check for deprecations
if ( $req_ver_hi ) {
$req_ver = $this->_computeVersionValue($req_ver_hi);
if ( $mpd_ver > $req_ver ) {
$this->errStr = "Command '$cmd' has been deprecated in this version of MPD.";
return FALSE;
return TRUE;
/* _parseFileListResponse()
* Builds a multidimensional array with MPD response lists.
* NOTE: This function is used internally within the class. It should not be used.
function _parseFileListResponse($resp) {
if ( is_null($resp) ) {
return NULL;
} else {
$plistArray = array();
$plistLine = strtok($resp,"\n");
$plistFile = "";
$plCounter = -1;
while ( $plistLine ) {
list ( $element, $value ) = split(": ",$plistLine);
if ( $element == "file" ) {
$plCounter++;
$plistFile = $value;
$plistArray[$plCounter]["file"] = $plistFile;
} else {
$plistArray[$plCounter][$element] = $value;
$plistLine = strtok("\n");
return $plistArray;
/* RefreshInfo()
* Updates all class properties with the values from the MPD server.
* NOTE: This function is automatically called upon Connect() as of v1.1.
function RefreshInfo() {
// Get the Server Statistics
$statStr = $this->SendCommand(MPD_CMD_STATISTICS);
if ( !$statStr ) {
return NULL;
} else {
$stats = array();
$statLine = strtok($statStr,"\n");
while ( $statLine ) {
list ( $element, $value ) = split(": ",$statLine);
$stats[$element] = $value;
$statLine = strtok("\n");
// Get the Server Status
$statusStr = $this->SendCommand(MPD_CMD_STATUS);
if ( ! $statusStr ) {
return NULL;
} else {
$status = array();
$statusLine = strtok($statusStr,"\n");
while ( $statusLine ) {
list ( $element, $value ) = split(": ",$statusLine);
$status[$element] = $value;
$statusLine = strtok("\n");
// Get the Playlist
$plStr = $this->SendCommand(MPD_CMD_PLLIST);
$this->playlist = $this->_parseFileListResponse($plStr);
$this->playlist_count = count($this->playlist);
// Set Misc Other Variables
$this->state = $status['state'];
if ( ($this->state == MPD_STATE_PLAYING) || ($this->state == MPD_STATE_PAUSED) ) {
$this->current_track_id = $status['song'];
list ($this->current_track_position, $this->current_track_length ) = split(":",$status['time']);
} else {
$this->current_track_id = -1;
$this->current_track_position = -1;
$this->current_track_length = -1;
$this->repeat = $status['repeat'];
$this->random = $status['random'];
$this->db_last_refreshed = $stats['db_update'];
$this->volume = $status['volume'];
$this->uptime = $stats['uptime'];
$this->playtime = $stats['playtime'];
$this->num_songs_played = $stats['songs_played'];
$this->num_artists = $stats['num_artists'];
$this->num_songs = $stats['num_songs'];
$this->num_albums = $stats['num_albums'];
return TRUE;
/* ------------------ DEPRECATED METHODS -------------------*/
/* GetStatistics()
* Retrieves the 'statistics' variables from the server and tosses them into an array.
* NOTE: This function really should not be used. Instead, use $this->[variable]. The function
* will most likely be deprecated in future releases.
function GetStatistics() {
if ( $this->debugging ) echo "mpd->GetStatistics()\n";
$stats = $this->SendCommand(MPD_CMD_STATISTICS);
if ( !$stats ) {
return NULL;
} else {
$statsArray = array();
$statsLine = strtok($stats,"\n");
while ( $statsLine ) {
list ( $element, $value ) = split(": ",$statsLine);
$statsArray[$element] = $value;
$statsLine = strtok("\n");
if ( $this->debugging ) echo "mpd->GetStatistics() / return: " . print_r($statsArray) ."\n";
return $statsArray;
/* GetStatus()
* Retrieves the 'status' variables from the server and tosses them into an array.
* NOTE: This function really should not be used. Instead, use $this->[variable]. The function
* will most likely be deprecated in future releases.
function GetStatus() {
if ( $this->debugging ) echo "mpd->GetStatus()\n";
$status = $this->SendCommand(MPD_CMD_STATUS);
if ( ! $status ) {
return NULL;
} else {
$statusArray = array();
$statusLine = strtok($status,"\n");
while ( $statusLine ) {
list ( $element, $value ) = split(": ",$statusLine);
$statusArray[$element] = $value;
$statusLine = strtok("\n");
if ( $this->debugging ) echo "mpd->GetStatus() / return: " . print_r($statusArray) ."\n";
return $statusArray;
/* GetVolume()
* Retrieves the mixer volume from the server.
* NOTE: This function really should not be used. Instead, use $this->volume. The function
* will most likely be deprecated in future releases.
function GetVolume() {
if ( $this->debugging ) echo "mpd->GetVolume()\n";
$volLine = $this->SendCommand(MPD_CMD_STATUS);
if ( ! $volLine ) {
return NULL;
} else {
list ($vol) = sscanf($volLine,"volume: %d");
if ( $this->debugging ) echo "mpd->GetVolume() / return: $vol\n";
return $vol;
/* GetPlaylist()
* Retrieves the playlist from the server and tosses it into a multidimensional array.
* NOTE: This function really should not be used. Instead, use $this->playlist. The function
* will most likely be deprecated in future releases.
function GetPlaylist() {
if ( $this->debugging ) echo "mpd->GetPlaylist()\n";
$resp = $this->SendCommand(MPD_CMD_PLLIST);
$playlist = $this->_parseFileListResponse($resp);
if ( $this->debugging ) echo "mpd->GetPlaylist() / return ".print_r($playlist)."\n";
return $playlist;
/* ----------------- Command compatibility tables --------------------- */
var $COMPATIBILITY_MIN_TBL = array(
MPD_CMD_SEEK => "0.9.1" ,
MPD_CMD_PLMOVE => "0.9.1" ,
MPD_CMD_RANDOM => "0.9.1" ,
MPD_CMD_PLSWAPTRACK => "0.9.1" ,
MPD_CMD_PLMOVETRACK => "0.9.1" ,
MPD_CMD_PASSWORD => "0.10.0" ,
MPD_CMD_SETVOL => "0.10.0"
var $COMPATIBILITY_MAX_TBL = array(
MPD_CMD_VOLUME => "0.10.0"
} // ---------------------------- end of class ------------------------------
?>
and the HTML output:
<HTML>
<style type="text/css"><!-- .defaultText { font-family: Arial, Helvetica, sans-serif; font-size: 9pt; font-style: normal; font-weight: normal; color: #111111} .err { color: #DD3333 } --></style>
<BODY class="defaultText">
connected == FALSE ) {
echo "Error Connecting: " . $myMpd->errStr;
} else {
switch ($_REQUEST[m]) {
case "add":
if ( is_null($myMpd->PLAdd($_REQUEST[filename])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "rem":
if ( is_null($myMpd->PLRemove($_REQUEST[id])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "setvol":
if ( is_null($myMpd->SetVolume($_REQUEST[vol])) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "play":
if ( is_null($myMpd->Play()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "stop":
if ( is_null($myMpd->Stop()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
case "pause":
if ( is_null($myMpd->Pause()) ) echo "<SPAN CLASS=err>ERROR: " .$myMpd->errStr."</SPAN>";
break;
default:
break;
?>
<DIV ALIGN=CENTER>[ <A HREF="<? echo $_SERVER[PHP_SELF] ?>">Refresh Page</A> ]</DIV>
<HR>
<B>Connected to MPD Version mpd_version ?> at host ?>:port ?></B><BR>
State:
state) {
case MPD_STATE_PLAYING: echo "MPD is Playing [<A HREF='".$_SERVER[PHP_SELF]."?m=pause'>Pause</A>] [<A HREF='".$_SERVER[PHP_SELF]."?m=stop'>Stop</A>]"; break;
case MPD_STATE_PAUSED: echo "MPD is Paused [<A HREF='".$_SERVER[PHP_SELF]."?m=pause'>Unpause</A>]"; break;
case MPD_STATE_STOPPED: echo "MPD is Stopped [<A HREF='".$_SERVER[PHP_SELF]."?m=play'>Play</A>]"; break;
default: echo "(Unknown State!)"; break;
?>
<BR>
Volume: volume ?> [ <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=0'>0</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=25'>25</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=75'>75</A> | <A HREF='<? echo $_SERVER[PHP_SELF] ?>?m=setvol&vol=100'>100</A> ]<BR>
Uptime: uptime) ?><BR>
Playtime: playtime) ?><BR>
state == MPD_STATE_PLAYING or $myMpd->state == MPD_STATE_PAUSED ) { ?>
Currently Playing: playlist[$myMpd->current_track_id]['Artist']." - ".$myMpd->playlist[$myMpd->current_track_id]['Title'] ?><BR>
Track Position: current_track_position."/".$myMpd->current_track_length." (".(round(($myMpd->current_track_position/$myMpd->current_track_length),2)*100)."%)" ?><BR>
Playlist Position: current_track_id+1)."/".$myMpd->playlist_count." (".(round((($myMpd->current_track_id+1)/$myMpd->playlist_count),2)*100)."%)" ?><BR>
<HR>
<B>Playlist - Total: playlist_count ?> tracks (Click to Remove)</B><BR>
playlist) ) echo "ERROR: " .$myMpd->errStr."\n";
else {
foreach ($myMpd->playlist as $id => $entry) {
echo ( $id == $myMpd->current_track_id ? "<B>" : "" ) . ($id+1) . ". <A HREF='".$_SERVER[PHP_SELF]."?m=rem&id=".$id."'>".$entry['Artist']." - ".$entry['Title']."</A>".( $id == $myMpd->current_track_id ? "</B>" : "" )."<BR>\n";
?>
<HR>
<B>Sample Search for the String 'U2' (Click to Add to Playlist)</B><BR>
Search(MPD_SEARCH_ARTIST,'U2');
if ( is_null($sl) ) echo "ERROR: " .$myMpd->errStr."\n";
else {
foreach ($sl as $id => $entry) {
echo ($id+1) . ": <A HREF='".$_SERVER[PHP_SELF]."?m=add&filename=".urlencode($entry['file'])."'>".$entry['Artist']." - ".$entry['Title']."</A><BR>\n";
if ( count($sl) == 0 ) echo "<I>No results returned from search.</I>";
// Example of how you would use Bulk Add features of MPD
// $myarray = array();
// $myarray[0] = "ACDC - Thunderstruck.mp3";
// $myarray[1] = "ACDC - Back In Black.mp3";
// $myarray[2] = "ACDC - Hells Bells.mp3";
// if ( is_null($myMpd->PLAddBulk($myarray)) ) echo "ERROR: ".$myMpd->errStr."\n";
?>
<HR>
<B>Artist List</B><BR>
GetArtists()) ) echo "ERROR: " .$myMpd->errStr."\n";
else {
while(list($key, $value) = each($ar) ) {
echo ($key+1) . ". " . $value . "<BR>";
$myMpd->Disconnect();
// Used to make number of seconds perty.
function secToTimeStr($secs) {
$days = ($secs%604800)/86400;
$hours = (($secs%604800)%86400)/3600;
$minutes = ((($secs%604800)%86400)%3600)/60;
$seconds = (((($secs%604800)%86400)%3600)%60);
if (round($days)) $timestring .= round($days)."d ";
if (round($hours)) $timestring .= round($hours)."h ";
if (round($minutes)) $timestring .= round($minutes)."m";
if (!round($minutes)&&!round($hours)&&!round($days)) $timestring.=" ".round($seconds)."s";
return $timestring;
?>
</BODY></HTML>
As you can see it doesn't seem to understand the pointer operator. Do I have to enable anything in the PHP config files or something?It's set up correctly. Also, it does parse PHP, just not after the arrow.
Here is my php.ini:
; With mbstring support this will automatically be converted into the encoding
; given by corresponding encode setting. When empty mbstring.internal_encoding
; is used. For the decode settings you can distinguish between motorola and
; intel byte order. A decode setting cannot be empty.
; http://php.net/exif.encode-unicode
;exif.encode_unicode = ISO-8859-15
; http://php.net/exif.decode-unicode-motorola
;exif.decode_unicode_motorola = UCS-2BE
; http://php.net/exif.decode-unicode-intel
;exif.decode_unicode_intel = UCS-2LE
; http://php.net/exif.encode-jis
;exif.encode_jis =
; http://php.net/exif.decode-jis-motorola
;exif.decode_jis_motorola = JIS
; http://php.net/exif.decode-jis-intel
;exif.decode_jis_intel = JIS
[Tidy]
; The path to a default tidy configuration file to use when using tidy
; http://php.net/tidy.default-config
;tidy.default_config = /usr/local/lib/php/default.tcfg
; Should tidy clean and repair output automatically?
; WARNING: Do not use this option if you are generating non-html content
; such as dynamic images
; http://php.net/tidy.clean-output
tidy.clean_output = Off
[soap]
; Enables or disables WSDL caching feature.
; http://php.net/soap.wsdl-cache-enabled
soap.wsdl_cache_enabled=1
; Sets the directory name where SOAP extension will put cache files.
; http://php.net/soap.wsdl-cache-dir
soap.wsdl_cache_dir="/tmp"
; (time to live) Sets the number of second while cached file will be used
; instead of original one.
; http://php.net/soap.wsdl-cache-ttl
soap.wsdl_cache_ttl=86400
; Sets the size of the cache limit. (Max. number of WSDL files to cache)
soap.wsdl_cache_limit = 5
[sysvshm]
; A default size of the shared memory segment
;sysvshm.init_mem = 10000
[ldap]
; Sets the maximum number of open links or -1 for unlimited.
ldap.max_links = -1
[mcrypt]
; For more information about mcrypt settings see http://php.net/mcrypt-module-open
; Directory where to load mcrypt algorithms
; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
;mcrypt.algorithms_dir=
; Directory where to load mcrypt modes
; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
;mcrypt.modes_dir=
[dba]
;dba.default_handler=
; Local Variables:
; tab-width: 4
; End:
Last edited by BaconPie (2010-11-04 20:11:33)
Maybe you are looking for
-
Can I run two separate ITune Accounts & Libraries and ipods on one computer
I have a friend visiting for a month and they want to use their IPod Nano and ITunes account on my computer. i.e. purchase and download their own songs via Itunes, sync with their Ipod etc. the same way they would on their own home computer, while th
-
I updated my 3GS with the latest update. But it doesn't work. Still I only see the Apple Icon on the display and almost every two minutes I get the sound of resetting/rebooting itself by the phone. So, what can I do?
-
CTC DI all-in-one fails at Step: Upload Default ACL Settings
Hi, i need your help. I tried to install a NWDI on a SolMan (Rel. NW7.01 SP06). I deployed the necessary SCAs (DI_CBS, DI_CMS and DI_DTR =7.01SP6). At the next point I'd like to use the wizard for the initial setup (DI all-in-one) and here are my pro
-
MacBook Pro not reading some DVD's.
My 18 month old, 15" MacBook Pro refuses to read some DVD's, even a new DVD out of the packet. When I insert the disc I can hear the drive whir up but it doesn't whir up as far as it does when I put a DVD in that it will read. The drive just keeps wh
-
How can i import contacts from a palm phone to my N73?