<?php
/**
* eventCreator
*
* View, Create and Update iCal event in a HTML form and get output in a iCal file
*
* copyright (c) 2007 Kjell-Inge Gustafsson kigkonsult
* www.kigkonsult.se/iCalcreator/eventCreator/index.php
* hide@address.com
* updated 20070608
*
* 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
*
* This setup script is to be included in all other scripts
*
**/
defined( '_VALID_KIG' ) or die( 'Direct Access to this location is not allowed.' );
/** some functions.. . */
/** check data */
function eccheckParams( $_REQUEST ) {
if( 0 == count( $_REQUEST ))
return FALSE;
elseif( isset( $_REQUEST['v'] ) && ( 1 == count( $_REQUEST )))
return FALSE;
elseif( isset( $_REQUEST['v']['task'] ) &&
( 'uploadFile' == $_REQUEST['v']['task'] ) &&
isset( $_REQUEST['MAX_FILE_SIZE'] ) &&
( 2 == count( $_REQUEST )))
return FALSE;
elseif( !isset( $_REQUEST['f'] ))
return FALSE;
$keys = array_keys( $_REQUEST );
$errkeys = FALSE;
foreach( $keys as $key ) {
if( !in_array( $key, array( 'd', 'f', 'l', 'u', 'o' )))
$errkeys++;
}
return $errkeys;
}
function & ecconfigCalendar( $v ) {
/** create a new calendar object */
// echo test( $v, 'ecconfigCalendar'); // test ###
$calendar = new vcalendar();
if( empty( $v['directory'] ))
$v['directory'] = ( defined( 'ECEVENTSELECTDIR' )) ? ECEVENTSELECTDIR : ECCACHE;
$calendar->setConfig( 'directory', $v['directory'] );
if( !empty( $v['filename'] ))
$calendar->setConfig( 'filename', $v['filename'] );
if( defined( 'ECUNIQUEID' ))
$calendar->setConfig( 'unique_id', ECUNIQUEID );
//$fileinfo=$calendar->getConfig('fileinfo');echo test( $fileinfo,'ecconfigCalendar');//test ###
return $calendar;
}
function & eccreateDefaultEvent() {
$event = new vevent();
if( defined( 'ECUNIQUEID' ))
$event->setConfig( 'unique_id', ECUNIQUEID );
$event->setProperty( 'created' );
$event->setProperty( 'dtstart', array( 'timestamp' => date( 'U' )));
if( 0 < @ECEVENTDURATION )
$event->setProperty( 'dtend', ( array( 'timestamp' => ( date( 'U' ) + ( 3600 * ECEVENTDURATION )))));
if( defined( 'ECEVENTORGANIZERDEFAULT' ) && ( FALSE !== ECEVENTORGANIZERDEFAULT ))
$event->setProperty( 'ORGANIZER', ECEVENTORGANIZERDEFAULT );
if( defined( 'ECALLOWTRIGGERDISPLAY' ) && ( TRUE === ECALLOWTRIGGERDISPLAY ) &&
defined( 'ECTRIGGERDISPLAYDEFAULT' )) {
$alarm = new valarm();
$alarm->setProperty( 'action', 'DISPLAY' );
$alarm->setProperty( 'trigger', ectriggerMin2arr ( ECTRIGGERDISPLAYDEFAULT ));
$event->setComponent( $alarm );
}
if( defined( 'ECALLOWTRIGGEREMAIL' ) && ( TRUE === ECALLOWTRIGGEREMAIL ) &&
defined( 'ECTRIGGEREMAILDEFAULT' )) {
$alarm = new valarm();
$alarm->setProperty( 'action', 'EMAIL' );
$alarm->setProperty( 'trigger', ectriggerMin2arr ( ECTRIGGEREMAILDEFAULT ));
$event->setComponent( $alarm );
}
return $event;
}
function ecdate2timestamp ( $date ) {
/** convert date array to datestamp */
if( !is_array( $date ))
return date;
if( isset( $date['timestamp'] ))
return date;
$date['year'] = ( isset( $date['Year'] )) ? $date['Year'] : $date['year'];
$date['month'] = ( isset( $date['Month'] )) ? $date['Month'] : $date['month'];
$date['day'] = ( isset( $date['Day'] )) ? $date['Day'] : $date['day'];
if( !isset( $date['hour'] ))
$date['hour'] = ( isset( $date['Hour'] )) ? $date['Hour'] : 0;
if( !isset( $date['min'] ))
$date['min'] = ( isset( $date['Minute'] )) ? $date['Minute'] : 0;
$date['timestamp'] = mktime ( $date['hour']
, $date['min']
, 0
, $date['month']
, $date['day']
, $date['year'] );
return $date;
}
function ecFetchEvent( & $v, & $compsinfo, $ordno=null, $eventordno=null, $uid=null, $first=FALSE ) {
//echo "<b>ecFetchEvent IN</b> ordno=$ordno eventordno=$eventordno uid=$uid first=$first<br />\n"; // test ###
// echo test( $compsinfo ,''); // test ###
$v['eventordno'] = $v['ordno'] = $v['previous'] = $v['next'] = $v['compscnt'] = $v['UID'] = null;
$v['eventcnt'] = 0;
$v['compscnt'] = count( $compsinfo );
foreach( $compsinfo as $cix => $compinfo) {
if( 'vevent' != $compinfo['type'] )
continue;
// foreach($compinfo as $k=>$v) if(!is_array($v)) echo "$k=>$v "; echo "<br />\n"; // test ###
$v['eventcnt']++;
if( !empty( $v['ordno'] )) {
if( !isset( $v['next'] ))
$v['next'] = $v['eventcnt'];
continue;
}
if(( !empty( $ordno ) && ( $ordno == $compinfo['ordno'] )) || // träff på ordno
( !empty( $eventordno ) && ( $eventordno == $v['eventcnt'] )) || // träff på eventordno
( !empty( $uid ) && ( $uid == $compinfo['uid'] )) || // träff på uid
$first ) { // träff på första
$v['eventordno'] = $v['eventcnt'];
$v['ordno'] = $compinfo['ordno'];
$v['UID'] = $compinfo['uid'];
}
else
$v['previous'] = $v['eventcnt'];
}
//echo "<b>ecFetchEvent UT</b> ordno={$v['ordno']} eventordno={$v['eventordno']} uid={$v['UID']}"; // test
//echo " previous={$v['previous']} next={$v['next']} compscnt={$v['compscnt']} eventcnt={$v['eventcnt']}<br />\n"; // test ###
if( empty( $v['ordno'] )) {
$v['previous'] = null;
return FALSE;
}
else {
return TRUE;
}
}
function ecFileSort( & $v ) {
$calendar = new vcalendar();
$calendar->setConfig( 'directory', $v['directory'] );
$calendar->setConfig( 'filename', $v['filename'] );
if( defined( 'ECUNIQUEID' ))
$calendar->setConfig( 'unique_id', ECUNIQUEID );
$fileinfo = $calendar->getConfig( 'fileinfo');
//echo test( $fileinfo, 'ecFileSort'); // test ###
$result = FALSE;
if( 0 < $fileinfo[2] ) {
$calendar->parse();
$calendar->sort();
$calendar->saveCalendar();
$result = TRUE;
}
$calendar = null;
return $result;
}
function ecgetFilelist( $directory ) {
$dir = new DirectoryIterator( $directory );
$filelist = array();
foreach( $dir as $file ) {
$filename = $file->getFilename();
if( $file->isFile() && ( 'ics' == substr( $filename, -3 ))) {
$filenameShort = substr( $filename, 0, strlen($filename) - 4 ); // skip ext.
$filenameShort = ( 14 < strlen($filenameShort ))
? substr( $filenameShort, 0, 12 ).'..' : $filenameShort;
$filelist[$filename] = $filenameShort;
}
}
if( 0 < count( $filelist )) {
GLOBAL $EClang;
$filelist[''] = $EClang['selectFilelabel'];
ksort( $filelist );
return $filelist;
}
else
return null;
}
function ecGetFlags() {
$dir = new DirectoryIterator( ECDIR.DIRECTORY_SEPARATOR.'languages' );
$filelist = array();
foreach( $dir as $file ) {
$filename = $file->getFilename();
if( $file->isFile() && ( 'php' == substr( $filename, -3 )))
$filelist[] = substr( $filename, 5, 2 );
}
return $filelist;
}
if( TRUE === @ECREDIRECTONCLOSE ) {
$v['redirecturl'] = ECREDIRECTONCLOSEURL;
if( isset( $ECREDIRECTONCLOSEURLPARAMS ) &&
is_array( $ECREDIRECTONCLOSEURLPARAMS )) {
$delim = '?';
foreach( $ECREDIRECTONCLOSEURLPARAMS as $key => $value ) {
if( isset( $v[$key] )) {
$v['redirecturl'] .= $delim.$value.'='.htmlentities( $v[$key] );
$delim = '&';
}
}
}
}
function ecgetRedirectUrl( & $v ) {
$url = ECREDIRECTONCLOSEURL;
if( isset( $ECREDIRECTONCLOSEURLPARAMS ) &&
is_array( $ECREDIRECTONCLOSEURLPARAMS )) {
$delim = '?';
foreach( $ECREDIRECTONCLOSEURLPARAMS as $key => $value ) {
if( isset( $v[$key] )) {
$url .= $delim.$value.'='.htmlentities( $v[$key] );
$delim = '&';
}
}
}
return $url;
}
function ecimpfile( $directory, $impfilename, $filetype ) {
/** file upload managing */
$filetype = strtolower($filetype);
$dirfile = null;
$fileerror = FALSE;
$userfile2 = ( isset($_FILES[$impfilename]['tmp_name']) ? $_FILES[$impfilename]['tmp_name'] : "" );
$userfile_name = ( isset($_FILES[$impfilename]['name']) ? trim( $_FILES[$impfilename]['name'] ) : "" );
// echo test( ($_FILES, "ecimpfile" ); // test ###
if( !empty( $_FILES[$impfilename] )) {
$dirfile = $directory.DIRECTORY_SEPARATOR.$userfile_name;
$path_parts = pathinfo( $dirfile );
$fnameNoExtlen = strlen( $path_parts['basename'] ) - strlen( $filetype ) - 1;
$fnameNoExt = substr( $path_parts['basename'], 0, $fnameNoExtlen );
if( is_file( $dirfile )) {
GLOBAL $EClang;
$text = $EClang['fileOverwriteQ'];
echo "<script>if(!confirm('".$text."')) document.location.href='".ECURL."'; </script>";
unlink ( $dirfile );
}
clearstatcache();
if( empty( $userfile_name ))
$fileerror = 1;
elseif( eregi( "[^0-9a-zA-Z_]", $fnameNoExt ) || ( 3 > strlen( $fnameNoExt )))
$fileerror = 2;
elseif( strtolower( $path_parts['extension'] ) != $filetype )
$fileerror = 3;
elseif (0 >= $_FILES[$impfilename]['size'])
$fileerror = 4;
elseif( !move_uploaded_file( $userfile2, $dirfile )) {
switch ($_FILES[$impfilename]['error']) {
case 4: $fileerror = 5; break;
case 3: $fileerror = 6; break;
case 2: $fileerror = 7; break;
case 1: $fileerror = 8; break;
default: // UPLOAD_ERR_OK
case 0: break;
}
}
elseif( !chmod( $dirfile, 0777 ))
$fileerror = 9;
}
else
$fileerror = 10;
if( $fileerror ) {
if( is_file( $userfile2 )) {
unlink( $userfile2 );
clearstatcache();
}
return $fileerror;
}
else
return $userfile_name;
}
function ecinitNewEvent( & $v ) {
$v['CREATED'] = null;
$v['SUMMARY'] = null;
$v['DTSTAMP'] = null;
$v['DTSTART'] = null;
$v['DTEND'] = null;
$v['LOCATION'] = null;
$v['ORGANIZER'] = null;
$v['DESCRIPTION'] = null;
$v['TRIGGERdisplay'] = null;
$v['TRIGGERemail'] = null;
$v['CLASS'] = null;
$v['TRANSP'] = null;
$v['URL'] = null;
$v['UID'] = null;
$v['COMMENT'] = array();
$v['ATTENDEE'] = array();
}
function ecloadEvent( & $v, $event ) {
/** load from event object to $v array */
ecinitNewEvent( $v );
// update from $event
while( $prop = $event->getProperty( 'attendee' )) {
$v['ATTENDEE'][] = $prop;
}
$v['CLASS'] = $event->getProperty( 'class' );
while( $prop = $event->getProperty( 'comment' )) {
$v['COMMENT'][] = $prop;
}
$v['CREATED'] = $event->getProperty( 'created' );
$v['DESCRIPTION'] = $event->getProperty( 'description' );
$v['DTSTAMP'] = $event->getProperty( 'dtstamp' );
$v['DTSTART'] = $d1 = $event->getProperty( 'dtstart' );
if( $prop = $event->getProperty( 'duration' ))
$v['DTEND'] = ecdate2timestamp( $event->duration2date() );
elseif( $prop = $event->getProperty( 'dtend' ))
$v['DTEND'] = ecdate2timestamp( $prop );
// echo test($v['DTEND'], 'loadEvent enddate'); // test ###
$v['DTSTART'] = ecdate2timestamp( $v['DTSTART'] );
$v['LASTMODIFIED'] = $event->getProperty( 'last-modified' );
$v['LOCATION'] = $event->getProperty( 'location' );
$v['ORGANIZER'] = $event->getProperty( 'organizer' );
$v['SUMMARY'] = $event->getProperty( 'summary' );
$v['TRANSP'] = $event->getProperty( 'transp' );
$v['UID'] = $event->getProperty( 'uid' );
$v['URL'] = $event->getProperty( 'url' );
$tropt = null;
while(( $alert = $event->getComponent()) &&
( empty( $v['TRIGGERdisplay'] ) || empty( $v['TRIGGERemail'] ))) {
$prop = $alert->getProperty( 'trigger' );
$trigger = 0;
if( !empty( $prop['year'] )) {
// convert UTC date to duration, if possible
$d3 = mktime( $prop['hour']
, $prop['min']
, $prop['sec'] + (int) date('Z') // UTC offset
, $prop['month']
, $prop['day']
, $prop['year'] );
$duration = $v['DTSTART']['timestamp'] - $d3;
if( 0 > $duration )
continue; // can't take care of trigger AFTER startdate, only before (?)
$trigger = (int) floor( $duration / 60 ); // convert to minutes
}
else {
if( isset( $prop['week'] ))
$trigger += ( $prop['week'] * 7 * 24 * 60 );
if( isset( $prop['day'] ))
$trigger += ( $prop['day'] * 24 * 60 );
if( isset( $prop['hour'] ))
$trigger += ( $prop['hour'] * 60 );
if( isset( $prop['min'] ))
$trigger += $prop['min'];
}
// adapt to $EClang TRIGGER_options (internal, we use minutes)
if( !$tropt ) {
GLOBAL $EClang;
$tropt = array_keys( $EClang['TRIGGER_options'] );
rsort( $tropt, SORT_NUMERIC );
}
foreach( $tropt as $troption ) {
if( $trigger >= $troption ) {
$trigger = $troption;
break;
}
}
if( $prop = $alert->getProperty( 'action' )) {
if(( 'DISPLAY' == strtoupper( $prop )) && empty( $v['TRIGGERdisplay'] ))
$v['TRIGGERdisplay'] = $trigger;
elseif(( 'EMAIL' == strtoupper( $prop )) && empty( $v['TRIGGERemail'] )) {
$v['TRIGGERemail'] = $trigger;
while( $prop = $alert->getProperty( 'attendee' )) {
if( !in_array( $prop, $v['ATTENDEE'] ))
$v['ATTENDEE'][] = $prop;
}
}
}
}
}
function & ecloadFile( $v ) {
/** load calendar from file */
// echo test( $v, 'ecloadFile IN'); // test ###
$calendar = & ecconfigCalendar( $v );
$fileinfo = $calendar->getConfig( 'fileinfo');
// echo test( $fileinfo, 'ecloadFile'); // test ###
if( 0 < $fileinfo[2] )
$calendar->parse();
// echo test( $v, 'ecloadFile UT'); // test ###
return $calendar;
}
function ecremFiles( $directory, $timeout=0 , $includeSubdirs=FALSE) {
if( 0 == $timeout )
return;
/** remove old iCal/xCal/rsscal files from $dir, older than $timeout secs */
$filetypes = array( 'ics', 'rss', 'xml', 'xcs' );
$rmDateTime = mktime (date('G'), date('i'), date('s')-$timeout, date("n") ,date("d"), date("Y"));
$dir = new DirectoryIterator( $directory );
$filecnt = 0;
foreach($dir as $file ) {
$dirfilename = $directory.DIRECTORY_SEPARATOR.$file->getFilename();
if( '.' == substr( $dirfilename, -1 ))
continue;
if( $file->isFile()) {
if( in_array( substr( $dirfilename, -3 ), $filetypes ) &&
( $file->getMTime() < $rmDateTime ))
$res = @unlink( $dirfilename );
else
$filecnt++;
}
elseif( $includeSubdirs &&
$file->isDir() &&
( 0 >= ecremFiles( $dirfilename, $timeout )))
$res = @rmdir( $dirfilename );
}
return $filecnt;
}
function & ecsaveEvent( & $v, $calendar=FALSE ) {
/** save to a new event object in calendar object */
if( FALSE !== $calendar ) {
$calendar->setConfig( 'directory', $v['directory'] );
$calendar->setConfig( 'filename', $v['filename'] );
if( defined( 'ECUNIQUEID' ))
$calendar->setConfig( 'unique_id', ECUNIQUEID );
}
else {
$calendar = & ecloadFile( $v );
$fileinfo = $calendar->getConfig( 'fileinfo ');
if( 0 < $fileinfo[2] )
$calendar->parse();
}
$event = new vevent();
if( !empty( $v['DTSTAMP']['year'] ))
$event->setProperty( 'DTSTAMP', $v['DTSTAMP'] );
$v['DTSTAMP'] = ecdate2timestamp( $event->getProperty( 'dtstamp' ));
$date = ( empty( $v['CREATED']['year'] ))
? $v['DTSTAMP'] : ecdate2timestamp( $v['CREATED'] );
$event->setProperty( 'CREATED', $date );
$compdate = ( !empty( $v['LAST-MODIFIED']['year'] ))
? ecdate2timestamp( $v['LAST-MODIFIED'] )
: $date;
// update last-mod if 24 hours passed since last update, just another day.. .
$now = mktime(date('H') - 24,date('i'),date('s'),date('m'),date('d'),date('Y'));
if( $now > $compdate['timestamp'] )
$event->setProperty( 'LAST-MODIFIED' );
$v['DTSTART'] = ecdate2timestamp( $v['DTSTART'] );
// echo test($a=array($v['DTEND'], $v['chkb'] ), 'saveEvent enddate+chkb'); // test ###
if( !empty( $v['DTEND'] ) && empty( $v['chkb'] )) {
$v['DTEND'] = ecdate2timestamp ( $v['DTEND'] );
/** check from/to date order */
if( $v['DTEND']['timestamp'] < $v['DTSTART']['timestamp'] ) {
$tmp = $v['DTEND'];
$v['DTEND'] = $v['DTSTART'];
$v['DTSTART'] = $tmp;
}
$durseconds = $v['DTEND']['timestamp'] - $v['DTSTART']['timestamp'];
/** use Duration if period (in days) is less than ECENDDATE2DURATION */
if(( 0 < @ECENDDATE2DURATION ) && ( 7 > @ECENDDATE2DURATION ) &&
( $durseconds <= ( ECENDDATE2DURATION * 24 * 60 * 60 )))
$event->setProperty( 'duration', array( 'sec' => $durseconds ));
else
$event->setProperty( 'dtend', $v['DTEND'] );
}
$event->setProperty( 'dtstart', $v['DTSTART'] );
if( !empty( $v['SUMMARY'] ))
$event->setProperty( 'summary', $v['SUMMARY'] );
if( !empty( $v['LOCATION'] ))
$event->setProperty( 'location', $v['LOCATION'] );
if( !empty( $v['ORGANIZER'] ))
$event->setProperty( 'organizer', $v['ORGANIZER'] );
if( !empty( $v['DESCRIPTION'] ))
$event->setProperty( 'description', $v['DESCRIPTION'] );
if( !empty( $v['CLASS'] ))
$event->setProperty( 'class', $v['CLASS'] );
if( !empty( $v['TRANSP'] ))
$event->setProperty( 'transp', $v['TRANSP'] );
if( !empty( $v['URL'] ) && ( 'http://' != $v['URL'] ))
$event->setProperty( 'url', $v['URL'] );
if( !empty( $v['UID'] ))
$event->setProperty( 'uid', $v['UID'] );
if( isset( $v['COMMENT'] ) && is_array( $v['COMMENT'] ) && ( 0 < $v['COMMENTcnt'] )) {
foreach( $v['COMMENT'] as $comment ) {
$comment = trim( $comment );
if( !empty( $comment ))
$event->setProperty( 'comment', $comment );
}
}
if( isset( $v['ATTENDEE'] ) && is_array( $v['ATTENDEE'] ) && ( 0 < $v['ATTENDEEcnt'] )) {
foreach( $v['ATTENDEE'] as $attendee ) {
$attendee = trim( $attendee );
if( !empty( $attendee ))
$event->setProperty( 'attendee', $attendee );
}
}
if(( !empty( $v['TRIGGERemail'] ) && ( 0 < $v['ATTENDEEcnt'] )) ||
!empty( $v['TRIGGERdisplay'] )) {
GLOBAL $EClang;
$date = ((0 == date('H', $v['DTSTART']['timestamp'])) &&
(0 == date('i', $v['DTSTART']['timestamp'])))
? date('j M', $v['DTSTART']['timestamp'])
: date('j M, H:i', $v['DTSTART']['timestamp']);
$description = $EClang['TRIGGERlabel'].': '.$v['DESCRIPTION'].' : '.$date;
$actions = array();
if( !empty( $v['TRIGGERemail'] ) && ( 0 < $v['ATTENDEEcnt'] ))
$actions['EMAIL'] = $v['TRIGGERemail'];
if( !empty( $v['TRIGGERdisplay'] ))
$actions['DISPLAY'] = $v['TRIGGERdisplay'];
foreach( $actions as $action => $trigger) {
$alarm = new valarm();
$alarm->setProperty( 'action', $action );
$alarm->setProperty( 'description', $description );
if( 'EMAIL' == $action ) {
$alarm->setProperty( 'summary', $v['SUMMARY'] );
foreach( $v['ATTENDEE'] as $attendee ) {
$attendee = trim( $attendee );
if( !empty( $attendee ))
$alarm->setProperty( 'attendee', $attendee );
}
}
$alarm->setProperty( 'trigger', ectriggerMin2arr ( $trigger ));
$event->setComponent( $alarm );
}
}
if( empty( $v['UID'] ))
$v['UID'] = $event->getProperty( 'UID' );
$saveid = ( !empty($v['ordno'] )) ? $v['ordno'] : $v['UID'];
$calendar->setComponent( $event, $saveid );
if( TRUE === @ECSETTIMEZONE ) {
$calendar->setProperty( 'X-WR-TIMEZONE', ECTIMEZONE );
}
/** sort and save file */
$calendar->sort();
$calendar->saveCalendar();
$compsinfo = $calendar->getConfig( 'compsinfo' );
/** select the event again after sort with key=uid (unique id!!!) */
ecFetchEvent( $v, $compsinfo, FALSE, FALSE, $v['UID'] );
return $calendar;
}
function ectriggerMin2arr ( $triggerMinutes ) {
$triggarr = array();
$triggarr['week'] = floor( $triggerMinutes / ( 60 * 24 * 7 ));
$triggerMinutes = $triggerMinutes % ( 60 * 24 * 7 );
$triggarr['day'] = floor( $triggerMinutes / ( 60 * 24 ));
$triggerMinutes = $triggerMinutes % ( 60 * 24 );
$triggarr['hour'] = floor( $triggerMinutes / 60 );
$triggarr['min'] = $triggerMinutes % 60;
return $triggarr;
}
function traversePrint(&$content, $msg=null){
/** print content into file, testing */
$fp = fopen('Asignal.txt', 'w');
fwrite($fp, test($content, $msg));
fclose($fp);
}
function test(&$content, $msg=null, $tab=null) {
/** return content as a string, testing */
$str = $tab;
if( !empty( $msg ))
$str .= "<br />\n<b>$msg</b><br />\n";
if( is_array($content)) {
foreach($content as $key => $value) {
$str .= "$key =>";
if( is_array($value)) {
$str .= "<br />\n".test($value, '', $tab.'..');
$str .= "<br />\n";
}
else
$str .= $value." ";
}
}
else
$str .= $content."<br />\n";
return $str;
}
?>