<?
/*
*
* $Id: common.inc.php,v 1.72 2005/09/07 20:35:12 ledjon Exp $
*
* phpLedMailer - v1.x
*
* by Jon Coulter
* http://www.ledscripts.com/
*
* Changes:
* - None yet
*
*/
// set error reporting level
//error_reporting(E_ALL & ~E_NOTICE);
error_reporting(error_reporting() & ~E_NOTICE);
// auto-start session(s)
if(! headers_sent( ) )
{
session_start( );
}
// install file still there?
if(file_exists( dirname(__FILE__) . '/install.php' )
&& !defined('PHPLEDMAILER_INSTALLER'))
{
// make sure that install.php doesn't exist anymore
die("Please delete install.php before you continue " .
"(or run install.php, if you have not yet configured phpLedMailer.)");
}
// config file
require_once(dirname(__FILE__) . '/config.inc.php');
// ADODB database abstraction layer
define('ADODB_ASSOC_CASE', 0); // lower case
require_once(dirname(__FILE__) . '/lib/adodb/adodb.inc.php');
require_once(dirname(__FILE__) . '/lib/html/class.LedHTML.php');
require_once(dirname(__FILE__) . '/lib/template/class.LedTemplate.php');
// moved to $db->SetFetchMode(ADODB_FETCH_ASSOC);
// $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
class phpLedMailer
{
var $version = '1.8';
var $db = null;
var $html = null;
var $template = null;
var $errstr = null;
var $mailer = null;
function phpLedMailer( $config )
{
$this->config = $config;
$this->template = new LedTemplate( );
// database specific fixes
if($config['db']['type'] == "mssql")
{
//$this->db->maxParameterLen = pow(2, 31) - 1;
// odbc mssql (native mssql is limited to 6.5 functionality)
$this->db = NewADOConnection('odbc_mssql') or die("Unable to create object: " . __LINE__);
$dsn = sprintf("Driver={SQL Server};Server=%s;Database=%s;",
$config['db']['host'],
$config['db']['db']
);
$this->db->Connect($dsn, $config['db']['user'], $config['db']['pass'])
or die("<b>Unable to connect to database!</b> Make sure you have the database configuration correct in config.inc.php");
}
else
{
// oracle stuff
if($config['db']['type'] == 'oracle'
|| $config['db']['type'] == 'oci8')
{
$config['db']['type'] = 'oci8po'; // portable version
}
// sqlite
if($config['db']['type'] == 'sqlite')
{
$config['db']['type'] = 'sqlitepo'; // portable version
$config['db']['host'] = $config['db']['db'];
}
// form a dsn for adodb
$dsn = sprintf("%s://%s:%s@%s/%s",
$config['db']['type'],
$config['db']['user'],
$config['db']['pass'],
$config['db']['host'],
$config['db']['db']
);
// echo $dsn;
$this->db = NewADOConnection($dsn)
or die("<b>Unable to connect to database!</b> Make sure you have the database configuration correct in config.inc.php");
// remove these stupid quotes
// this has to be rigged per-database
if($this->db->dataProvider == 'mysql'
|| $this->db->dataProvider == 'postgres'
|| $this->db->databaseType == 'sqlitepo')
{
$this->db->fmtTimeStamp = str_replace("'", "", $this->db->fmtTimeStamp);
}
}
$this->db->SetFetchMode(ADODB_FETCH_ASSOC);
// load config from the database
$this->_LoadConfig( );
// html settings
$this->html = new LedHTML(
array(
'width' => '700',
'size' => 1,
'border' => 1,
'cellspacing' => 0,
'cellpadding' => 0,
'bordercolor' => "#669999",
'align' => 'center',
'input_class' => 'input',
)
);
// I don't really like this -- it effectivly
// doubles the amount of memory the incoming params
// take at any point in time, plus they can then be
// gotten out of sync.
$this->param = (object) $this->html->_param;
$this->server = (object) $_SERVER;
// debuging
//$this->db->debug = 99;
//echo $this->db->OffsetDate(-5, $this->db->sysTimeStamp);
//exit;
//echo $this->db->sysTimeStamp;
//exit;
//echo $this->db->SQLDate('Y');
//exit;
/*
echo '<pre>';
var_dump($this->db);
exit;
*/
}
// get a config value
// up to 3 levels deep
function config( $key, $key2 = null )
{
$val = $this->config[$key];
if( isset($key2) )
{
$val = $val[$key2];
}
return $val;
}
function set_config( $key, $val, $key2 = null )
{
if(isset($key2))
{
$key = $key . '_' . $key2;
}
$this->config[$key] = $val;
}
function _VersionCheckURL( )
{
$url = sprintf(
'http://www.ledscripts.com/vcheck/vcheck.php?key=%s&ver=%s',
'phpLedMailer',
$this->version
);
return $url;
}
function _LoadConfig( )
{
// see if we have this table
if($this->TableExists('plm_config') == false)
{
return false;
}
$f_config = array( );
// read in from config table
$res = $this->db->Execute("select conf_key, conf_val from plm_config where conf_val is not null")
or die($this->db->ErrorMsg( ));
while($row = $res->FetchNextObj( ))
{
// don't want to deal with empty values
if(empty($row->conf_val))
{
continue;
}
// handle they need for key recursion
$conf = array( );
$keys = explode(',', $row->conf_key);
$this->_LoadConfig_rec_func( $conf, $keys, $row->conf_val );
$f_config = $this->rec_array_merge($f_config, $conf);
}
//var_dump($f_config);
//echo $f_config['version'] . $this->version;
if($f_config['version'] != $this->version)
{
echo "<font color=white>WARNING: Version in database is not the same as this software is reporting. Please rerun the data sync (under Utilites) ASAP!<br></font>";
}
$this->config = $this->rec_array_merge($this->config, $f_config);
return true;
}
function _LoadConfig_rec_func( &$holder, &$keys, $val )
{
if($elm = array_shift($keys))
{
if(count($keys) > 0)
{
// at all other levels
if(! is_array($holder[$elm]) )
{
$holder[$elm] = array( );
}
$this->_LoadConfig_rec_func($holder[$elm], $keys, $val);
}
else
{
// at the top (final) level, assign $val
$holder[$elm] = $val;
}
}
}
/*
Credit where it's due:
brian at vermonster dot com
http://us4.php.net/array_merge_recursive
-- comments section
*/
function rec_array_merge($paArray1, $paArray2)
{
if (!is_array($paArray1) or !is_array($paArray2))
{
return $paArray2;
}
foreach ($paArray2 AS $sKey2 => $sValue2)
{
$paArray1[$sKey2] = $this->rec_array_merge(@$paArray1[$sKey2], $sValue2);
}
return $paArray1;
}
function TableExists( $table )
{
$dict = NewDataDictionary($this->db);
$cols = $dict->MetaColumns( $table );
if( empty($cols) )
{
// no table (yet -- need to re-sync tables)
return false;
}
else
{
return true;
}
}
function auth( $user = null, $pass = null )
{
if(! $user )
{
$user = $this->param->_auth_user;
if(! $user )
{
$user = $_SESSION['user'];
}
}
if(! $pass )
{
$pass = $this->param->_auth_pass;
if(! $pass )
{
$pass = $_SESSION['pass'];
}
}
$auth_tag = $_COOKIE['plm_auth_tag'];
//var_dump($_COOKIE);
if(!($user && $pass))
{
// maybe look it up based on a key?
if($auth_tag)
{
//die("cookie: $auth_tag");
// attempt to set $user and $pass
// based on this cookie
$out = $this->getAuthDetails( $auth_tag );
if($out)
{
list($user, $pass) = $out;
}
}
}
// check the database
if(($this->user = $this->validLogin($user, $pass)) === false)
{
//$this->send_auth( );
if($user and $pass)
{
$this->template->Set('login_error', 'Invalid login details');
}
return false;
}
else
{
if($this->param->remember_login)
{
// set an auth_tag
$auth_tag = $this->setAuthTag($this->user->userid, $user, $pass);
}
$_SESSION['user'] = $user;
$_SESSION['pass'] = $pass;
// otherwise, true, daddy-O
return $this->user;
}
return false;
}
// set an authorization tag (to remember login details)
function setAuthTag( $userid, $u, $p )
{
if(! $this->TableExists('plm_cryptcheck'))
{
return false;
}
$crypt = $this->_getCrypt( );
// make up a key
$key = uniqid('c');
$crypt->setkey( $key );
// encrypt the username and password
$e_u = base64_encode($crypt->encrypt($u));
$e_p = base64_encode($crypt->encrypt($p));
$euserid = base64_encode($crypt->encrypt($userid));
// insert the new record
$args = array(
'userid' => $userid,
'euserid' => $euserid,
'username' => $e_u,
'password' => $e_p,
'accessdatetime' => $this->db->DBTimeStamp(time())
);
$this->db->AutoExecute('plm_cryptcheck', $args, 'INSERT')
or die($this->db->ErrorMsg( ));
// set the cookie
setcookie(
'plm_auth_tag',
$userid . ':' . $key, // userid:key
time() + 157680000 // 5 years
);
//die($key);
return $key;
}
// fetch the username and password based on
// and auth_tag
function getAuthDetails( $key )
{
if(! $this->TableExists('plm_cryptcheck'))
{
return false;
}
// poll the database
list($userid, $key) = explode(':', $key, 2);
// invalid cookie
if(! $key )
{
return false;
}
// find the record in the datbase
$res = $this->db->Execute("select euserid, username, password from plm_cryptcheck where userid = ?",
array( intval($userid) )
) or die($this->db->ErrorMsg( ));
if($res->RowCount( ) <= 0)
{
return false;
}
// we can now deal with this overhead
$crypt = $this->_getCrypt( );
$crypt->setkey( $key );
while($row = $res->FetchNextObj( ))
{
// pull these out of plain text
$euserid = base64_decode( $row->euserid );
$user = base64_decode( $row->username );
$pass = base64_decode( $row->password );
$uid = $crypt->decrypt($euserid);
// see if this matches a record in the database
if(strlen($uid) != strlen((string)intval($uid)))
{
// not a proper decryption
continue;
}
$uid = intval($uid);
//$this->db->debug=99;
$count = $this->db->GetOne("select count(*) from plm_users where userid = " . $uid);
if($count != 1)
{
// invalid id found
continue;
}
// otherwise, this must be the correct key
$u = $crypt->decrypt($user);
$p = $crypt->decrypt($pass);
$record = array(
'accessdatetime' => $this->db->DBTimeStamp(time())
);
$this->db->AutoExecute('plm_cryptcheck', $record, 'UPDATE',
"euserid = " . $this->db->qstr($row->euserid) .
" and username = " . $this->db->qstr($row->username) .
" and password = " . $this->db->qstr($row->password)
) or die($this->db->ErrorMsg());
/*
$this->db->Execute(
"update plm_cryptcheck set accessdatetime = " .
// a nice little oracle-ism here
$this->db->DBTimeStamp(time()) .
"
where euserid = ? and username = ? and password = ?",
array( $row->euserid,
$row->username,
$row->password
)
) or die($this->db->ErrorMsg( ));
*/
// Delete some older keys.
// at this point, if they haven't been here in a year,
// delete the record
$this->db->Execute(
"delete from plm_cryptcheck
where accessdatetime < " .
$this->db->OffsetDate(-365, $this->db->sysTimeStamp)
) or die($this->db->ErrorMsg( ));
return array($u, $p);
}
return false;
}
function clearAuthTag( $key = null )
{
if(! $this->TableExists('plm_cryptcheck'))
{
return false;
}
//var_dump($_COOKIE);
if(! $key )
{
list($user, $key) = explode(':', $_COOKIE['plm_auth_tag'], 2);
}
//die($key);
if(! $key )
{
// probably never set
return;
}
$crypt = $this->_getCrypt( );
$crypt->setkey( $key );
// delete from database
$this->db->Execute("delete from plm_cryptcheck where euserid = ?",
array( base64_encode($crypt->encrypt($this->user->userid)))
) or die($this->db->ErrorMsg( ));
// remove cookie
setcookie(
'plm_auth_tag',
'',
time() - 157680000 // - 5 years
);
return true;
}
function _getCrypt( )
{
require_once(dirname(__FILE__) . '/lib/crypt/cast128.php');
return new cast128();
}
function loginPage( )
{
// var_dump($_SESSION);
$this->template->loadTemplate('login', '_admin_templates/login.html');
$this->template->Set('login_action',
$this->link( )
);
if(! $this->template->isValSet('login_error') )
{
$this->template->Set('login_error', '');
}
return $this->template->Parse('login');
}
function validLogin( $user, $pass )
{
if(empty($user) and empty($pass))
{
return false;
}
// ->ErrorMsg()
$sql = $this->db->Prepare("select userid, username from plm_users " .
" where username = ? and password = ?");
//var_dump($sql);
$result = $this->db->Execute($sql, array($user, md5($pass)));
if( !$result )
{
//var_dump($this->db);
exit;
}
//or die("Error with login: " . $this->db->ErrorMsg());
// valid login details?
if( $result->RecordCount() <= 0 )
{
return false;
}
else
{
return $result->FetchNextObj( );
}
}
// no longer used
// but kept none the less
function send_auth( )
{
header('WWW-Authenticate: Basic realm="phpLedMailer Admin Area"');
header("HTTP/1.0 401 Unauthorized");
echo "Invalid Login Details\n";
exit(0);
}
// create a relative link with given arguments
function link( $args = null, $clean = false )
{
$self = $this->server->PHP_SELF;
if($args !== false)
{
$self .= '?';
$start = ($clean ? array( ) : $_GET);
if(is_array($args))
{
$start = array_merge($start, $args);
}
foreach($start as $k => $v)
{
$self .= '&' . urlencode($k) . '=' . urlencode($v);
}
}
return $self;
}
// the baseurl: http://mysite.com/
function baseurl( )
{
if($this->config['baseurl'])
{
// no verification on user-input values here
return $this->config['baseurl'];
}
$port = $this->server->SERVER_PORT;
$is_ssl = $port == 443;
$prefix = ($is_ssl ? 'https://' : 'http://');
return sprintf("%s%s",
$prefix,
$this->server->HTTP_HOST
);
}
function sendNoCache( )
{
if(headers_sent( ))
{
// too late, nothing we can do here
// except avoid more errors
return;
}
// Date in the past
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
// always modified
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
// HTTP/1.1
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
// HTTP/1.0
header("Pragma: no-cache");
}
// run a given user-defined method
function runMethod( $m )
{
if(!function_exists($m))
{
die("Unable to find function: $m");
}
return call_user_func($m, $this);
}
function error( $msg )
{
$this->errstr = $msg;
return false;
}
function errstr( )
{
return $this->errstr;
}
// return a (cached) mail object to the caller
function mailer( )
{
if(isset($this->mailer))
{
return $this->mailer;
}
else
{
require_once(dirname(__FILE__) . '/lib/mail/class.phpmailer.php');
//$this->mailer = new plmPHPMailer();
$this->mailer = new PHPMailer();
$this->mailer->SetLanguage("en", dirname(__FILE__) . '/lib/mail/');
if($this->config['mailserv']['type'] == 'smtp')
{
$this->mailer->IsSMTP();
$this->mailer->Host = $this->config['mailserv']['host'];
}
$this->mailer->From = $this->config['listemail'];
$this->mailer->FromName = $this->config['listname'];
// recursive call to ourself here
return $this->mailer( );
}
}
function makeMenu( )
{
$ret = $ret2 = null;
$items = array(
'Main' => array( 'mod' => 'start' ),
'Subscribers' => array( 'mod' => 'subscribers', 'a' => 'list' ),
'Mail Items' => array( 'mod' => 'mailitems', 'a' => 'list' ),
'Send Mail' => array( 'mod' => 'senditems', 'a' => 'list' ),
'Users' => array( 'mod' => 'users', 'a' => 'list' ),
'Configuration' => array( 'mod' => 'config' ),
'Utilities' => array('mod' => 'utils' ),
'Help' => array( 'mod' => 'help' )
);
$parts = array( );
$pct = ceil(100 / count($items));
foreach($items as $name => $pts)
{
$link = $this->link( $pts, true );
$parts[] = '<td bgcolor="#66ffff" width="' . $pct . '%"
onmouseover="javascript:navChangeFocus(this)"
onmouseout="javascript:navChangeFocus(this)"
align="center">' .
$this->html->ahref(
$link,
$name
) .
'</td>';
$this->template->Set(
'self_link_' . strtolower($name),
$link
);
}
for($i = 0; $i < count($parts); $i++)
{
if($i > 0)
{
$ret .= '<td width="0" bgcolor="#000000"><img src="images/1x1.gif" width="2" height="1"></td>';
$ret2 .= '<td><img src="images/1x1.gif" width="2" height="2"></td>';
}
$ret .= $parts[$i];
$ret2 .= '<td><img src="images/1x1.gif" width="1" height="2"></td>';
}
return sprintf('<table width="100%%" border="0"
cellspacing="0" cellpadding="0"><tr>%s</tr><tr bgcolor="#000000">%s</tr></table>', $ret, $ret2);
}
/*
// menu on left
// looks like butt
function makeMenu( )
{
$ret = $ret2 = null;
$items = array(
'Main' => array( 'mod' => 'start' ),
'Subscribers' => array( 'mod' => 'subscribers', 'a' => 'list' ),
'Mail Items' => array( 'mod' => 'mailitems', 'a' => 'list' ),
'Send Mail' => array( 'mod' => 'senditems', 'a' => 'list' ),
'Users' => array( 'mod' => 'users', 'a' => 'list' ),
'Utilities' => array('mod' => 'utils' ),
'Help' => array( 'mod' => 'help' )
);
$parts = array( );
$pct = ceil(100 / count($items));
foreach($items as $name => $pts)
{
$link = $this->link( $pts, true );
$pct = '100';
$parts[] = '<tr><td bgcolor="#66ffff" width="' . $pct . '%"
onmouseover="javascript:navChangeFocus(this)"
onmouseout="javascript:navChangeFocus(this)"
align="center">' .
$this->html->ahref(
$link,
$name
) .
'</td></tr>';
$this->template->Set(
'self_link_' . strtolower($name),
$link
);
}
for($i = 0; $i < count($parts); $i++)
{
$ret .= '<tr><td width="0" bgcolor="#000000"><img src="images/1x1.gif" width="2" height="1"></td></tr>';
if($i > 0)
{
$ret2 .= '<tr><td><img src="images/1x1.gif" width="2" height="2"></td></tr>';
}
$ret .= $parts[$i];
$ret2 .= '<td><img src="images/1x1.gif" width="1" height="2"></td>';
}
return sprintf('<table width="120" border="0"
cellspacing="0" cellpadding="0"><tr>%s</tr><tr bgcolor="#000000">%s</tr></table>', $ret, $ret2);
}
*/
// see if a subscriber exists
// based on a key => value pair,
// and return the subscriberid from the key/value pair
function subscriberExists( $key, $val )
{
$sql = $this->db->Prepare("select subscriberid from plm_subscribers where $key = ?");
$res = $this->db->Execute($sql, array($val)) or die($this->db->ErrorMsg());
if($res->RecordCount( ) <= 0)
{
return false;
}
else
{
$obj = $res->FetchNextObj( );
return $obj->subscriberid;
}
}
// add a subscriber (in pending mode)
// with optional arg to send validation email
function addPendingSubscriber( $args, $send_validation = true )
{
$this->db->BeginTrans( );
$key = $this->subQueue( $args, 's' )
or die("Error creating queue");
if($send_validation)
{
if( ! $this->sendVerificationEmail( $key, 's' ) )
{
$this->db->RollbackTrans( );
return $this->error( $this->errstr( ) );
}
}
$this->db->CommitTrans( );
return $key;
}
// delete a subscriber
function delSubscriber( $sid, $send_validation = true )
{
$this->db->BeginTrans( );
$sql = $this->db->Prepare("select * from plm_subscribers where subscriberid = ?");
$res = $this->db->Execute($sql, array($sid)) or die($this->db->ErrorMsg());
if($res->RecordCount( ) <= 0)
{
return $this->error("Invalid subscriberid");
}
$args = $res->FetchRow( );
$key = $this->subQueue( $args, 'u' );
if(! $key )
{
return $this->error("Error creating queue: " . $this->errstr( ));
}
if($send_validation)
{
if( ! $this->sendVerificationEmail( $key, 'u' ) )
{
$this->db->RollBackTrans( );
return $this->error( $this->errstr( ) );
}
}
$this->db->CommitTrans( );
return $key;
}
// send either a subscribe or unsubscribe verification email
function sendVerificationEmail( $key, $action )
{
$sql = $this->db->Prepare("select * from plm_sub_queue where keyhash = ?");
$result = $this->db->Execute($sql, array($key)) or die($this->db->ErrorMsg( ));
if($result->RecordCount( ) <= 0)
{
return $this->error("Unable to send verification email (no rows returned for key): " .
$this->db->ErrorMsg( ) );
}
$obj = $result->FetchNextObj( );
$args = (array) unserialize($obj->data);
$mail = $this->mailer( );
$t = new LedTemplate( );
$t->loadTemplate('email_verification',
(
$action == 's' ? 'templates/email_verification.html'
: 'templates/email_unsub_verification.html'
)
);
$t->Set('listname', $this->config['listname']);
$t->Set('verify_url',
$this->baseurl( ) . dirname($this->link( false )) .
'/verify.php?a=' . $action . '&i=' . $key
);
$t->Set( $args );
$mail->Subject = sprintf("[%s] Verification E-Mail",
$this->config['listname']
);
$mail->Body = $t->Parse('email_verification');
$mail->AltBody = strip_tags($mail->Body);
$mail->AddAddress( $args['emailaddr'],
implode(' ', array($args['firstname'], $args['lastname']))
);
if(! $mail->Send( ) )
{
return $this->error("Unable to send email: " . $mail->ErrorInfo);
}
return true;
}
// verify a sub or unsubscribe of an address (with a key, passed to this)
function verifyAddress( $key )
{
// better looking death message
$die_msg = "Unable to complete verification process. Perhaps you have already verified your address?";
$sql = $this->db->Prepare("select * from plm_sub_queue where keyhash = ?");
$result = $this->db->Execute($sql, array($key)) or die($this->db->ErrorMsg( ));
if($result->RecordCount( ) <= 0)
{
//return $this->error("Unable to verify user (no rows returned for key: $key): " .
// $this->db->ErrorMsg( ) );
return $this->error($die_msg);
}
$obj = $result->FetchNextObj( );
$args = (array) unserialize($obj->data);
$this->db->BeginTrans( );
if($obj->action == 's')
{
// sub scribe
$args = array_merge($args,
array(
'pending' => 0,
'createdatetime' => $this->db->DBTimeStamp(time())
)
);
$ret = $this->db->AutoExecute('plm_subscribers', $args, 'INSERT');
if($ret == false)
{
//return $this->error( "Unable to create subscriber record: " . $this->db->ErrorMsg( ) );
return $this->error($die_msg);
}
$sid = db_insert_id( $this->db, 'plm_subscribers', 'subscriberid' );
}
else
{
// unsubscribe user
$sql = $this->db->Prepare("delete from plm_subscribers where subscriberid = ?");
$this->db->Execute($sql, array(intval($args['subscriberid'])))
or die($this->db->ErrorMsg( ));
}
// delete the old record now
$sql = $this->db->Prepare("delete from plm_sub_queue where keyhash = ?");
$this->db->Execute($sql, array($key))
or die($this->db->ErrorMsg( ));
$this->db->CommitTrans( );
return true;
}
// create a subscribe or unsubscrib queue
function subQueue( $args, $action = 's' )
{
if(! is_array( $args ) )
{
return $this->error("First argument must be an array");
}
// random, unique key
$key = md5(uniqid(chr(rand(65,122)) . chr(rand(65,122))));
/*
$ret = $this->db->insert(
'plm_sub_queue',
array(
'keyhash' => $key,
'data' => $this->db->escape(serialize($args)),
'action' => $action
),
array(
'queuedatetime' => 'now()'
)
) or die($this->db->errstr( ));
*/
//echo $this->db->qstr($this->db->qstr($this->db->DBTimeStamp(time())));
$record = array(
'keyhash' => $key,
'data' => serialize($args),
'action' => $action,
'queuedatetime' => $this->db->DBTimeStamp(time())
);
$ret = $this->db->AutoExecute('plm_sub_queue', $record, 'INSERT')
or die($this->db->ErrorMsg());
return $key;
}
// queue a message (mid) to one or all subscribers
function queueToSubscribers( $mid, $sid = null )
{
$mid = intval($mid);
if(! $mid )
{
return $this->error("Invalid mid!");
}
$where = null;
if(isset($sid))
{
$where = " and subscriberid = $sid ";
}
/*
$this->db->queryNoExec(
"delete from plm_message_queue
where messageid = " . $mid . $where
) or die($this->db->errstr( ));
*/
$sql = "delete from plm_message_queue where messageid = " . $mid . $where;
$this->db->Execute($sql) or die($this->db->ErrorMsg( ));
$sql = sprintf(
"insert into plm_message_queue
select %d, subscriberid, 0, null
from plm_subscribers
where 1=1 $where",
$mid
);
$this->db->Execute($sql) or die($this->db->ErrorMsg( ));
return true;
}
// get a message object
// based on a messageid
function getMailMessage( $mid )
{
$sql = sprintf("
select messageid, subject, content, contentplain
from plm_messages
where messageid = %d
", $mid
);
$result = $this->db->Execute( $sql )
or die($this->db->errstr( ));
if($result->RecordCount( ) <= 0)
{
return $this->error("Unable to find any message that match that mid!");
}
return new plmMailMessage( $this, $result->FetchNextObj( ) );
}
// simply returns true or false
// based on a regex
function ValidEmailFormat( $email )
{
// email validation
// taken from an asp example, but probably
// works pretty well anyway :)
// regEx.Pattern = "^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$"
$regex = '/^[a-z][\w\.-]*[a-z0-9]@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$/i';
return preg_match($regex, $email) ? true : false;
}
function cleanDeath( $msg )
{
$this->template->loadTemplate('die',
dirname(__FILE__) . '/templates/die.html');
$this->template->Set('die_reason', $msg);
die($this->template->Parse('die'));
}
// just a shortcut to determine if
// php is running in safe mode
function _safeMode( )
{
return ini_get('safe_mode');
}
// rebuild the database layout
// put here so that it can be called from
// install.php as well as anything else that would
// make use of the common class
// optional param $do_executes will actually execute all the code
function syncDBLayout( $do_executes = false )
{
// bad idea to not ignore user aborts
ignore_user_abort(true);
if($this->_safeMode( ))
{
set_time_limit(0); // no timeout (besides what the webserver does)
}
$ret = array();
$force_type = null;
// Allow sqlite to be created correctly
if($this->db->databaseType == 'sqlitepo')
{
$force_type = 'sqlite';
}
// yet another RIG for mysql
// without setting $_db_type = mysql
// it wont append a (stupid) key() entry to the create table
// for plm_message_queue for subscriberid
// because innodb foreign keys require
// an index for each field (in the child and parent tables)
// , with that field as the *first* item of it
// so we have to make up an index for this in mysql
$_db_type = $this->db->dataProvider;
require_once(dirname(__FILE__) . '/db_schema.php');
if(!is_array($meta_tables)
&& !is_array($meta_indexes))
{
return $this->error("Unable to find meta tables or indexes!");
}
// create dictionary object
$dict = NewDataDictionary($this->db, $force_type);
if(is_array($meta_tables))
{
foreach($meta_tables as $table => $vals)
{
//$sql = $dict->CreateTableSQL($table,
$sql = $dict->ChangeTableSQL($table,
$vals[0],
$vals[1]
);
for($i = 0; $i < count($sql); $i++)
{
$ret[] = str_replace(';;', ';', $sql[$i]);
}
}
}
// next we need to do meta_indexes
if(is_array($meta_indexes))
{
foreach($meta_indexes as $table => $vals)
{
foreach($vals as $index => $opts)
{
// drop first
$sql = $dict->DropIndexSQL( $index, $table );
for($i = 0; $i < count($sql); $i++)
{
$ret[] = $sql[$i];
}
$sql = $dict->CreateIndexSQL(
$index,
$table,
$opts[0],
$opts[1]
);
for($i = 0; $i < count($sql); $i++)
{
$ret[] = $sql[$i];
}
}
}
}
// execute these now?
if($do_executes)
{
// does this have a version value at all?
// if not, then we assume this is the install step
// and we need to init a bunch of values
$r = $this->_install_config_values( );
if(is_array($r))
{
$ret = array_merge($ret, $r);
}
if(! $this->isSetup( ) )
{
// nada
}
// add one more query to the list!
// this ensures that the current version
// is always in the database
$ret[] = "delete from plm_config where conf_key = 'version'";
$ret[] = "insert into plm_config values ('version', '$this->version')";
$return = '';
foreach($ret as $s)
{
$return .= "<b>Executing:</b>\n<br>$s;\n<br>";
// only make notes of errors
// don't die on them
if(! $this->db->Execute($s) )
{
$return .= "<font color=red>Error: " . $this->db->ErrorMsg( ) . "</font>";
}
else
{
$return .= "<font color=green>Successful</font>";
}
$return .= "\n\n<br><br>";
}
return $return;
}
else
{
return $ret;
}
}
function isSetup( )
{
$count = $this->db->GetOne("select count(*) from plm_config where conf_key = 'version'");
return ($count <= 0 ? false : true);
}
// addon to the above items
// this is where core-base-defaults
// are defined (hard-coded, infact)
function _install_config_values( )
{
$ret = array( );
$insert_values = array(
'testing' => 0,
'baseurl' => '', // no defaults for now
'itemsetsize' => 25,
'listemail' => 'hide@address.com',
'listname' => 'My Site\'s Mailing List',
'mailserv,host' => 'localhost',
'mailserv,type' => 'standard',
'require_email_validation' => 0,
'sendsize' => 10,
'ufnames,userfield1' => 'City',
'ufnames,userfield2' => 'State',
//'imageuploads' => 1,
'auto_version_check' => 1,
'validate_email_regex' => 1,
'webservice_key' => ''
);
// for new key values
$exists = $this->TableExists('plm_config');
// do the inserts
// and ignore any errors (since the values)
// may already exist, and we don't want to overwrite them
foreach($insert_values as $k => $v)
{
$c = 0;
if($exists)
{
// this could reset it to 1
// but is only run if the table exists
$c = $this->db->GetOne("select count(*) from plm_config where conf_key = '$k'");
}
// we want this to happen if
// the table doesn't exist, or the key doesn't exist
if($c <= 0)
{
$ret[] = sprintf("insert into plm_config (conf_key, conf_val) values (%s, %s)",
$this->db->qstr( $k ),
$this->db->qstr( $v )
);
}
}
return $ret;
}
// returns an object that represents a nusoap-style
// server handle
function Get_phpLedMailer_SOAPService( )
{
require_once(dirname(__FILE__) . '/lib/soap/class.phpLedMailer_SOAPService.php');
return new phpLedMailer_SOAPService( $this );
}
// get the current web service key
function GetWebServiceKey( )
{
// should actually get pulled in at runtime
return $this->config['webservice_key'];
if($this->TablExists('plm_config'))
{
$key = $this->db->GetOne("select conf_val from plm_config where conf_key = 'webservice_key'");
if($key)
{
return $key;
}
}
return false;
}
// this will only work in php5+
function __destruct( )
{
if(is_object($this->db))
{
$this->db->Close();
}
}
}
// a mail message that is ready to be sent to the users
// note: this is the user-created e-mails, not things like
// verifiation e-mails.
class plmMailMessage
{
var $mail = null;
var $p = null;
var $message = null;
var $current_tags = array( );
function plmMailMessage( &$parent, $message )
{
$this->p = &$parent;
$this->mail = $this->p->mailer( );
$this->message = $message;
}
function SetupMessage( )
{
$this->mail->Subject = $this->Parse( $this->message->subject );
$this->mail->Body = $this->Parse( $this->message->content );
$plain = $this->message->contentplain;
// default to a strip'd version of the above
if(empty($plain))
{
$plain = strip_tags( $this->message->content );
}
$this->mail->AltBody = $this->Parse( $plain );
}
function sendTo( $addr, $name = null, $tags = null )
{
if($this->p->config['testing'])
{
return true;
}
// {firstname}... tags
if(!is_array($tags))
{
$tags = array( );
}
// set these to be used in parse()
$this->current_tags = $tags;
if(!isset($name)
&& !is_array($addr))
{
die("invalid sendTo() usage " . __LINE__);
}
$this->mail->ClearAddresses( );
if(is_array($addr))
{
foreach($addr as $email => $name)
{
// call this function again
$this->sendTo( $email, $name );
}
}
else
{
// set the address
$this->mail->AddAddress( $addr, trim($name) );
}
// Call this to set the mail objects
// sub as subject and body
// and also to parse tags ({firstname} {lastname}) type stuff
$this->SetupMessage( );
// send the actual email
if( ! $this->mail->Send( ) )
{
return $this->p->error( $this->mail->ErrorInfo );
}
else
{
return true;
}
}
// parse the tags ({tagname})
// into the given $msg value that is
// passed in
// -- this is generally the subject and body
// of the message
function Parse( $msg )
{
$tags = $this->current_tags;
// invalid list of tags sent in
if(!is_array($tags))
{
return $msg;
}
// the actual replacement logic
foreach($tags as $k => $v)
{
$msg = str_replace('{' . $k . '}', $v, $msg);
}
return $msg;
}
function errstr( )
{
return $this->p->errstr( );
}
}
class plmDataSync
{
var $p = null; // parent object
function plmDataSync( &$p )
{
$this->p = &$p;
}
function isSyncing( $bit = null )
{
if( isset($bit) )
{
// delete no matter what
$this->p->db->Execute("delete from plm_config where conf_key = 'in_db_sync'")
or die($this->p->db->ErrorMsg( ));
if($bit)
{
// insert into the database if running
$this->p->db->Execute("insert into plm_config (conf_key, conf_val) values ('in_db_sync', '$bit')")
or die($this->p->db->ErrorMsg( ));
}
return true;
}
else
{
// else, return the current value, if at all
$r = $this->p->db->GetOne("select conf_val from plm_config where conf_key = 'in_db_sync'");
return ($r ? true : false);
}
}
function runSync( $bit = null )
{
$this->isSyncing(true);
$ret = $this->p->syncDBLayout( $bit );
$this->isSyncing(false);
return $ret;
}
}
// this is thanks to postgresql and seq names
// and oracle (also using sequences)
// we can probably apply this to about any database type
function db_insert_id( $db, $table = null, $col = null )
{
if(strtolower($db->dataProvider) == "postgres")
{
return $db->pg_insert_id( $table, $col );
}
else
{
if($db->dataProvider == 'oci8')
{
// the current value for this table's sequence
$sql = sprintf("SELECT (%s.currval) FROM DUAL",
'SEQ_' . strtoupper($table));
$id = $db->GetOne( $sql );
if($id === false)
{
// some error
// perhaps let them know?
}
return $id;
}
else
{
return $db->Insert_ID( );
}
}
}
?>