Merge pull request #956 from annando/master

New database system that uses PDO if present/Test script for doing database upgrades.
This commit is contained in:
Tobias Diekershoff 2014-05-09 21:55:01 +02:00
commit 31312ab1d2
33 changed files with 3430 additions and 109 deletions

BIN
images/buffer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -31,7 +31,10 @@ function bb_rearrange_link($shared) {
return($newshare);
}
function bb_remove_share_information($Text) {
function bb_remove_share_information($Text, $plaintext = false) {
if ($plaintext)
$Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism","[bookmark=$1]$1[/bookmark]", $Text);
$Text = preg_replace_callback("((.*?)\[class=(.*?)\](.*?)\[\/class\])ism","bb_cleanup_share",$Text);
return($Text);
}
@ -1070,3 +1073,4 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
return $Text;
}
?>

View file

@ -5,17 +5,17 @@
class Cache {
public static function get($key) {
if (function_exists("apc_fetch") AND function_exists("apc_exists"))
/*if (function_exists("apc_fetch") AND function_exists("apc_exists"))
if (apc_exists($key))
return(apc_fetch($key));
return(apc_fetch($key));*/
$r = q("SELECT `v` FROM `cache` WHERE `k`='%s' limit 1",
dbesc($key)
);
if (count($r)) {
if (function_exists("apc_store"))
apc_store($key, $r[0]['v'], 600);
/*if (function_exists("apc_store"))
apc_store($key, $r[0]['v'], 600);*/
return $r[0]['v'];
}
@ -29,8 +29,8 @@
dbesc($value),
dbesc(datetime_convert()));
if (function_exists("apc_store"))
apc_store($key, $value, 600);
/*if (function_exists("apc_store"))
apc_store($key, $value, 600);*/
}

View file

@ -19,8 +19,6 @@ if(! function_exists('load_config')) {
function load_config($family) {
global $a;
// To-Do: How to integrate APC here?
$r = q("SELECT * FROM `config` WHERE `cat` = '%s'", dbesc($family));
if(count($r)) {
foreach($r as $rr) {
@ -67,7 +65,7 @@ function get_config($family, $key, $instore = false) {
}
// If APC is enabled then fetch the data from there, else try XCache
if (function_exists("apc_fetch") AND function_exists("apc_exists"))
/*if (function_exists("apc_fetch") AND function_exists("apc_exists"))
if (apc_exists($family."|".$key)) {
$val = apc_fetch($family."|".$key);
$a->config[$family][$key] = $val;
@ -87,6 +85,7 @@ function get_config($family, $key, $instore = false) {
else
return $val;
}
*/
$ret = q("SELECT `v` FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1",
dbesc($family),
@ -98,10 +97,10 @@ function get_config($family, $key, $instore = false) {
$a->config[$family][$key] = $val;
// If APC is enabled then store the data there, else try XCache
if (function_exists("apc_store"))
/*if (function_exists("apc_store"))
apc_store($family."|".$key, $val, 600);
elseif (function_exists("xcache_set"))
xcache_set($family."|".$key, $val, 600);
xcache_set($family."|".$key, $val, 600);*/
return $val;
}
@ -109,10 +108,10 @@ function get_config($family, $key, $instore = false) {
$a->config[$family][$key] = '!<unset>!';
// If APC is enabled then store the data there, else try XCache
if (function_exists("apc_store"))
/*if (function_exists("apc_store"))
apc_store($family."|".$key, '!<unset>!', 600);
elseif (function_exists("xcache_set"))
xcache_set($family."|".$key, '!<unset>!', 600);
xcache_set($family."|".$key, '!<unset>!', 600);*/
}
return false;
}}
@ -157,10 +156,10 @@ function set_config($family,$key,$value) {
$a->config[$family][$key] = $value;
// If APC is enabled then store the data there, else try XCache
if (function_exists("apc_store"))
/*if (function_exists("apc_store"))
apc_store($family."|".$key, $value, 600);
elseif (function_exists("xcache_set"))
xcache_set($family."|".$key, $value, 600);
xcache_set($family."|".$key, $value, 600);*/
if($ret)
return $value;
@ -210,7 +209,7 @@ function get_pconfig($uid,$family, $key, $instore = false) {
}
// If APC is enabled then fetch the data from there, else try XCache
if (function_exists("apc_fetch") AND function_exists("apc_exists"))
/*if (function_exists("apc_fetch") AND function_exists("apc_exists"))
if (apc_exists($uid."|".$family."|".$key)) {
$val = apc_fetch($uid."|".$family."|".$key);
$a->config[$uid][$family][$key] = $val;
@ -229,7 +228,7 @@ function get_pconfig($uid,$family, $key, $instore = false) {
return false;
else
return $val;
}
}*/
$ret = q("SELECT `v` FROM `pconfig` WHERE `uid` = %d AND `cat` = '%s' AND `k` = '%s' LIMIT 1",
@ -243,10 +242,10 @@ function get_pconfig($uid,$family, $key, $instore = false) {
$a->config[$uid][$family][$key] = $val;
// If APC is enabled then store the data there, else try XCache
if (function_exists("apc_store"))
/*if (function_exists("apc_store"))
apc_store($uid."|".$family."|".$key, $val, 600);
elseif (function_exists("xcache_set"))
xcache_set($uid."|".$family."|".$key, $val, 600);
xcache_set($uid."|".$family."|".$key, $val, 600);*/
return $val;
}
@ -254,10 +253,10 @@ function get_pconfig($uid,$family, $key, $instore = false) {
$a->config[$uid][$family][$key] = '!<unset>!';
// If APC is enabled then store the data there, else try XCache
if (function_exists("apc_store"))
/*if (function_exists("apc_store"))
apc_store($uid."|".$family."|".$key, '!<unset>!', 600);
elseif (function_exists("xcache_set"))
xcache_set($uid."|".$family."|".$key, '!<unset>!', 600);
xcache_set($uid."|".$family."|".$key, '!<unset>!', 600);*/
}
return false;
}}
@ -273,10 +272,10 @@ function del_config($family,$key) {
dbesc($key)
);
// If APC is enabled then delete the data from there, else try XCache
if (function_exists("apc_delete"))
/*if (function_exists("apc_delete"))
apc_delete($family."|".$key);
elseif (function_exists("xcache_unset"))
xcache_unset($family."|".$key);
xcache_unset($family."|".$key);*/
return $ret;
}}
@ -316,10 +315,10 @@ function set_pconfig($uid,$family,$key,$value) {
$a->config[$uid][$family][$key] = $value;
// If APC is enabled then store the data there, else try XCache
if (function_exists("apc_store"))
/*if (function_exists("apc_store"))
apc_store($uid."|".$family."|".$key, $value, 600);
elseif (function_exists("xcache_set"))
xcache_set($uid."|".$family."|".$key, $value, 600);
xcache_set($uid."|".$family."|".$key, $value, 600);*/
if($ret)

View file

@ -1,5 +1,11 @@
<?php
# if PDO is avaible for mysql, use the new database abstraction
if(class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) {
require_once("library/dddbl2/dddbl.php");
require_once("include/dba_pdo.php");
}
require_once('include/datetime.php');
/**

340
include/dba_pdo.php Normal file
View file

@ -0,0 +1,340 @@
<?php
require_once('include/datetime.php');
$objDDDBLResultHandler = new \DDDBL\DataObjectPool('Result-Handler');
/**
* create handler, which returns just the PDOStatement object
* this allows usage of the cursor to scroll through
* big result-sets
*
**/
$cloPDOStatementResultHandler = function(\DDDBL\Queue $objQueue) {
$objPDO = $objQueue->getState()->get('PDOStatement');
$objQueue->getState()->update(array('result' => $objPDO));
# delete handler which closes the PDOStatement-cursor
# this will be done manual if using this handler
$objQueue->deleteHandler(QUEUE_CLOSE_CURSOR_POSITION);
};
$objDDDBLResultHandler->add('PDOStatement', array('HANDLER' => $cloPDOStatementResultHandler));
/**
*
* MySQL database class
*
* For debugging, insert 'dbg(1);' anywhere in the program flow.
* dbg(0); will turn it off. Logging is performed at LOGGER_DATA level.
* When logging, all binary info is converted to text and html entities are escaped so that
* the debugging stream is safe to view within both terminals and web pages.
*
*/
if(! class_exists('dba')) {
class dba {
private $debug = 0;
private $db;
private $result;
public $connected = false;
public $error = false;
function __construct($server,$user,$pass,$db,$install = false) {
global $a;
# work around, to store the database - configuration in DDDBL
$objDataObjectPool = new \DDDBL\DataObjectPool('Database-Definition');
$objDataObjectPool->add('DEFAULT', array('CONNECTION' => "mysql:host=$server;dbname=$db",
'USER' => $user,
'PASS' => $pass,
'DEFAULT' => true));
$stamp1 = microtime(true);
$server = trim($server);
$user = trim($user);
$pass = trim($pass);
$db = trim($db);
if (!(strlen($server) && strlen($user))){
$this->connected = false;
$this->db = null;
return;
}
if($install) {
if(strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1')) {
if(! dns_get_record($server, DNS_A + DNS_CNAME + DNS_PTR)) {
$this->error = sprintf( t('Cannot locate DNS info for database server \'%s\''), $server);
$this->connected = false;
$this->db = null;
return;
}
}
}
# etablish connection to database and store PDO object
\DDDBL\connect();
$this->db = \DDDBL\getDB();
if(\DDDBL\isConnected()) {
$this->connected = true;
}
if(! $this->connected) {
$this->db = null;
if(! $install)
system_unavailable();
}
$a->save_timestamp($stamp1, "network");
}
public function getdb() {
return $this->db;
}
public function q($sql, $onlyquery = false) {
global $a;
$strHandler = (true === $onlyquery) ? 'PDOStatement' : 'MULTI';
$strQueryAlias = md5($sql);
$strSQLType = strtoupper(strstr($sql, ' ', true));
$objPreparedQueryPool = new \DDDBL\DataObjectPool('Query-Definition');
# check if query do not exists till now, if so create its definition
if(!$objPreparedQueryPool->exists($strQueryAlias))
$objPreparedQueryPool->add($strQueryAlias, array('QUERY' => $sql,
'HANDLER' => $strHandler));
if((! $this->db) || (! $this->connected))
return false;
$this->error = '';
$stamp1 = microtime(true);
try {
$r = \DDDBL\get($strQueryAlias);
# bad workaround to emulate the bizzare behavior of mysql_query
if(in_array($strSQLType, array('INSERT', 'UPDATE', 'DELETE', 'CREATE', 'DROP', 'SET')))
$result = true;
} catch (\Exception $objException) {
$result = false;
$intErrorCode = $objPreparedQueryPool->get($strQueryAlias)->get('PDOStatement')->errorCode();
}
$stamp2 = microtime(true);
$duration = (float)($stamp2-$stamp1);
$a->save_timestamp($stamp1, "database");
if(x($a->config,'system') && x($a->config['system'],'db_log')) {
if (($duration > $a->config["system"]["db_loglimit"])) {
$duration = round($duration, 3);
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
@file_put_contents($a->config["system"]["db_log"], datetime_convert()."\t".$duration."\t".
basename($backtrace[1]["file"])."\t".
$backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t".
substr($sql, 0, 2000)."\n", FILE_APPEND);
}
}
if($intErrorCode)
$this->error = $intErrorCode;
if(strlen($this->error)) {
logger('dba: ' . $this->error);
}
if($this->debug) {
$mesg = '';
if($result === false)
$mesg = 'false';
elseif($result === true)
$mesg = 'true';
else {
# this needs fixing, but is a bug itself
#$mesg = mysql_num_rows($result) . ' results' . EOL;
}
$str = 'SQL = ' . printable($sql) . EOL . 'SQL returned ' . $mesg
. (($this->error) ? ' error: ' . $this->error : '')
. EOL;
logger('dba: ' . $str );
}
/**
* If dbfail.out exists, we will write any failed calls directly to it,
* regardless of any logging that may or may nor be in effect.
* These usually indicate SQL syntax errors that need to be resolved.
*/
if($result === false) {
logger('dba: ' . printable($sql) . ' returned false.' . "\n" . $this->error);
if(file_exists('dbfail.out'))
file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . ' returned false' . "\n" . $this->error . "\n", FILE_APPEND);
}
if(($result === true) || ($result === false))
return $result;
if ($onlyquery) {
$this->result = $r; # this will store an PDOStatement Object in result
$this->result->execute(); # execute the Statement, to get its result
return true;
}
//$a->save_timestamp($stamp1, "database");
if($this->debug)
logger('dba: ' . printable(print_r($r, true)));
return($r);
}
public function qfetch() {
if (false === $this->result)
return false;
return $this->result->fetch();
}
public function qclose() {
if ($this->result)
return $this->result->closeCursor();
}
public function dbg($dbg) {
$this->debug = $dbg;
}
public function escape($str) {
if($this->db && $this->connected) {
$strQuoted = $this->db->quote($str);
# this workaround is needed, because quote creates "'" and the beginning and the end
# of the string, which is correct. but until now the queries set this delimiter manually,
# so we must remove them from here and wait until everything uses prepared statements
return mb_substr($strQuoted, 1, mb_strlen($strQuoted) - 2);
}
}
function __destruct() {
if ($this->db)
\DDDBL\disconnect();
}
}}
if(! function_exists('printable')) {
function printable($s) {
$s = preg_replace("~([\x01-\x08\x0E-\x0F\x10-\x1F\x7F-\xFF])~",".", $s);
$s = str_replace("\x00",'.',$s);
if(x($_SERVER,'SERVER_NAME'))
$s = escape_tags($s);
return $s;
}}
// Procedural functions
if(! function_exists('dbg')) {
function dbg($state) {
global $db;
if($db)
$db->dbg($state);
}}
if(! function_exists('dbesc')) {
function dbesc($str) {
global $db;
if($db && $db->connected)
return($db->escape($str));
else
return(str_replace("'","\\'",$str));
}}
// Function: q($sql,$args);
// Description: execute SQL query with printf style args.
// Example: $r = q("SELECT * FROM `%s` WHERE `uid` = %d",
// 'user', 1);
if(! function_exists('q')) {
function q($sql) {
global $db;
$args = func_get_args();
unset($args[0]);
if($db && $db->connected) {
$stmt = @vsprintf($sql,$args); // Disabled warnings
//logger("dba: q: $stmt", LOGGER_ALL);
if($stmt === false)
logger('dba: vsprintf error: ' . print_r(debug_backtrace(),true), LOGGER_DEBUG);
return $db->q($stmt);
}
/**
*
* This will happen occasionally trying to store the
* session data after abnormal program termination
*
*/
logger('dba: no database: ' . print_r($args,true));
return false;
}}
/**
*
* Raw db query, no arguments
*
*/
if(! function_exists('dbq')) {
function dbq($sql) {
global $db;
if($db && $db->connected)
$ret = $db->q($sql);
else
$ret = false;
return $ret;
}}
// Caller is responsible for ensuring that any integer arguments to
// dbesc_array are actually integers and not malformed strings containing
// SQL injection vectors. All integer array elements should be specifically
// cast to int to avoid trouble.
if(! function_exists('dbesc_array_cb')) {
function dbesc_array_cb(&$item, $key) {
if(is_string($item))
$item = dbesc($item);
}}
if(! function_exists('dbesc_array')) {
function dbesc_array(&$arr) {
if(is_array($arr) && count($arr)) {
array_walk($arr,'dbesc_array_cb');
}
}}
if(! function_exists('dba_timer')) {
function dba_timer() {
return microtime(true);
}}

1227
include/dbstructure.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -329,7 +329,7 @@ function diaspora_msg_build($msg,$user,$contact,$prvkey,$pubkey,$public = false)
$b_outer_aes_key = base64_encode($outer_aes_key);
$outer_iv = random_string(16);
$b_outer_iv = base64_encode($outer_iv);
$handle = $user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
$padded_data = pkcs5_pad($msg,16);
@ -425,7 +425,7 @@ function diaspora_decode($importer,$xml) {
else {
$encrypted_header = json_decode(base64_decode($children->encrypted_header));
$encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key);
$ciphertext = base64_decode($encrypted_header->ciphertext);

View file

@ -239,4 +239,4 @@ function html2plain($html, $wraplength = 75, $compact = false)
return(trim($message));
}
?>

View file

@ -1173,3 +1173,27 @@ function original_url($url, $depth=1, $fetchbody = false) {
return($url);
}
if (!function_exists('short_link')) {
function short_link($url) {
require_once('library/slinky.php');
$slinky = new Slinky($url);
$yourls_url = get_config('yourls','url1');
if ($yourls_url) {
$yourls_username = get_config('yourls','username1');
$yourls_password = get_config('yourls', 'password1');
$yourls_ssl = get_config('yourls', 'ssl1');
$yourls = new Slinky_YourLS();
$yourls->set('username', $yourls_username);
$yourls->set('password', $yourls_password);
$yourls->set('ssl', $yourls_ssl);
$yourls->set('yourls-url', $yourls_url);
$slinky->set_cascade( array($yourls, new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL()));
} else {
// setup a cascade of shortening services
// try to get a short link from these services
// in the order ur1.ca, trim, id.gd, tinyurl
$slinky->set_cascade(array(new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL()));
}
return $slinky->short();
}};

179
include/plaintext.php Normal file
View file

@ -0,0 +1,179 @@
<?php
function get_attached_data($body) {
/*
- text:
- type: link, video, photo
- title:
- url:
- image:
- description:
- (thumbnail)
*/
$post = array();
if (preg_match_all("(\[class=(.*?)\](.*?)\[\/class\])ism",$body, $attached, PREG_SET_ORDER)) {
foreach ($attached AS $data) {
if (!in_array($data[1], array("type-link", "type-video", "type-photo")))
continue;
$post["type"] = substr($data[1], 5);
$post["text"] = trim(str_replace($data[0], "", $body));
$attacheddata = $data[2];
$URLSearchString = "^\[\]";
if (preg_match("/\[img\]([$URLSearchString]*)\[\/img\]/ism", $attacheddata, $matches))
$post["image"] = $matches[1];
if (preg_match("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) {
$post["url"] = $matches[1];
$post["title"] = $matches[2];
}
// Search for description
if (preg_match("/\[quote\](.*?)\[\/quote\]/ism", $attacheddata, $matches))
$post["description"] = $matches[1];
}
}
return($post);
}
function plaintext($a, $b, $limit = 0, $includedlinks = false) {
require_once("include/bbcode.php");
require_once("include/html2plain.php");
require_once("mod/parse_url.php");
require_once("include/network.php");
// Simplify image codes
$body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $b["body"]);
// At first look at data that is attached via "type-..." stuff
// This will hopefully replaced with a dedicated bbcode later
$post = get_attached_data($body);
// if nothing is found, it maybe having an image.
if (!isset($post["type"])) {
$URLSearchString = "^\[\]";
if (preg_match_all("(\[url=([$URLSearchString]*)\]\s*\[img\]([$URLSearchString]*)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) {
if (count($pictures) == 1) {
// Checking, if the link goes to a picture
$data = parseurl_getsiteinfo($pictures[0][1], true);
if ($data["type"] == "photo") {
$post["type"] = "photo";
if (isset($data["images"][0]))
$post["image"] = $data["images"][0]["src"];
else
$post["image"] = $data["url"];
$post["preview"] = $pictures[0][2];
$post["text"] = str_replace($pictures[0][0], "", $body);
} else {
$img_str = fetch_url($pictures[0][1]);
$tempfile = tempnam(get_config("system","temppath"), "cache");
file_put_contents($tempfile, $img_str);
$mime = image_type_to_mime_type(exif_imagetype($tempfile));
unlink($tempfile);
if (substr($mime, 0, 6) == "image/") {
$post["type"] = "photo";
$post["image"] = $pictures[0][1];
$post["preview"] = $pictures[0][2];
$post["text"] = str_replace($pictures[0][0], "", $body);
}
}
} elseif (count($pictures) > 1) {
$post["type"] = "link";
$post["url"] = $b["plink"];
$post["image"] = $pictures[0][2];
$post["text"] = $body;
}
} elseif (preg_match_all("(\[img\]([$URLSearchString]*)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) {
if (count($pictures) == 1) {
$post["type"] = "photo";
$post["image"] = $pictures[0][1];
$post["text"] = str_replace($pictures[0][0], "", $body);
} elseif (count($pictures) > 1) {
$post["type"] = "link";
$post["url"] = $b["plink"];
$post["image"] = $pictures[0][1];
$post["text"] = $body;
}
}
if (!isset($post["type"])) {
$post["type"] = "text";
$post["text"] = trim($body);
}
}
if (($b["title"] != "") AND ($post["text"] != ""))
$post["text"] = trim($b["title"]."\n\n".$post["text"]);
elseif ($b["title"] != "")
$post["text"] = trim($b["title"]);
$html = bbcode($post["text"], false, false, 2);
$msg = html2plain($html, 0, true);
$msg = trim(html_entity_decode($msg,ENT_QUOTES,'UTF-8'));
$link = "";
if ($includedlinks) {
if ($post["type"] == "link")
$link = $post["url"];
elseif ($post["type"] == "video")
$link = $post["url"];
elseif ($post["type"] == "photo")
$link = $post["image"];
if (($msg == "") AND isset($post["title"]))
$msg = trim($post["title"]);
if (($msg == "") AND isset($post["description"]))
$msg = trim($post["description"]);
// If the link is already contained in the post, then it neeedn't to be added again
// But: if the link is beyond the limit, then it has to be added.
if (($link != "") AND strstr($msg, $link)) {
$pos = strpos($msg, $link);
if (($limit == 0) OR ($pos < $limit))
$link = "";
}
}
if ($limit > 0) {
// Reduce multiple spaces
// When posted to a network with limited space, we try to gain space where possible
while (strpos($msg, " ") !== false)
$msg = str_replace(" ", " ", $msg);
// Twitter is using its own limiter, so we always assume that shortened links will have this length
if (strlen($link) > 0)
$limit = $limit - 23;
if (strlen($msg) > $limit) {
if (!isset($post["url"])) {
$limit = $limit - 23;
$post["url"] = $b["plink"];
}
$lines = explode("\n", $msg);
$msg = "";
$recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
foreach ($lines AS $row=>$line) {
if (strlen(trim($msg."\n".$line)) <= $limit)
$msg = trim($msg."\n".$line);
// Is the new message empty by now or is it a reshared message?
elseif (($msg == "") OR (($row == 1) AND (substr($msg, 0, 4) == $recycle)))
$msg = substr(substr(trim($msg."\n".$line), 0, $limit), 0, -3)."...";
}
}
}
$post["text"] = trim($msg);
return($post);
}
?>

View file

@ -197,14 +197,14 @@ function plugin_is_app($name) {
return true;
}
}
return false;
}}
/*
* parse plugin comment in search of plugin infos.
* like
*
*
* * Name: Plugin
* * Description: A plugin which plugs in
* * Version: 1.2.3
@ -222,7 +222,8 @@ function get_plugin_info($plugin){
'name' => $plugin,
'description' => "",
'author' => array(),
'version' => ""
'version' => "",
'status' => ""
);
if (!is_file("addon/$plugin/$plugin.php")) return $info;

View file

@ -0,0 +1,83 @@
<?php
namespace DDDBL;
require_once __DIR__ . '/inc/DataObjectPool.class.php';
require_once __DIR__ . '/inc/DataObject.class.php';
require_once __DIR__ . '/inc/Singleton.class.php';
require_once __DIR__ . '/inc/Queue.class.php';
require_once __DIR__ . '/inc/exceptions/UnexpectedParameterTypeException.class.php';
require_once __DIR__ . '/inc/exceptions/QueryException.class.php';
require_once __DIR__ . '/inc/database.func.php';
# position of handler, which gets the active database-connection into the queue
define('QUEUE_GET_DB_CONNECTION_POSITION', 10);
define('QUEUE_GET_QUERY_POSITION', 20);
define('QUEUE_BIND_DATA_TYPE_POSITION', 30);
define('QUEUE_PREPARE_QUERY_POSITION', 40);
define('QUEUE_EXECUTE_QUERY_POSITION', 50);
define('QUEUE_FORMAT_RESULT_POSITION', 60);
define('QUEUE_CLOSE_CURSOR_POSITION', 70);
###############################################
### set validator for "Database-Definition" ###
###############################################
$objDBDefinitionValidator = function ($arrValues) {
foreach(array('CONNECTION', 'USER', 'PASS') AS $strDefinitionField)
if(!isset($arrValues[$strDefinitionField]) || !is_string($arrValues[$strDefinitionField]))
return false;
if(isset($arrValues['PDO']) && !is_a($arrValues['PDO'], '\PDO'))
return false;
return true;
};
$objDataObjectPool = new DataObjectPool('Database-Definition');
$objDataObjectPool->setValidator($objDBDefinitionValidator);
############################################
### set validator for "Query-Definition" ###
############################################
$objQueryDefinitionValidator = function ($arrValues) {
if(!isset($arrValues['QUERY']) || !is_string($arrValues['QUERY']))
return false;
if(isset($arrValues['HANDLER']) && !is_string($arrValues['HANDLER']))
return false;
return true;
};
$objDataObjectPool = new DataObjectPool('Query-Definition');
$objDataObjectPool->setValidator($objQueryDefinitionValidator);
##########################################
### set validator for "Result-Handler" ###
##########################################
$objResultHandlerValidator = function ($arrValues) {
if(!isset($arrValues['HANDLER']) || !is_callable($arrValues['HANDLER']))
return false;
return true;
};
$objDataObjectPool = new DataObjectPool('Result-Handler');
$objDataObjectPool->setValidator($objResultHandlerValidator);
#########################################
### register queue and result handler ###
#########################################
require_once __DIR__ . '/handler/register_queue_handler.inc.php';
require_once __DIR__ . '/handler/register_result_handler.inc.php';

184
library/dddbl2/dddbl.php Normal file
View file

@ -0,0 +1,184 @@
<?php
namespace DDDBL;
require_once __DIR__ . '/config.inc.php';
/**
* @throws \Exception - if no parameter are given
* @throws UnexpectedParameterTypeException - if first parameter is not a string
*
* @returns (mixed) - the result of the query-definition execution
*
* expect a list of parameter with at least one value. the
* list is handled over to the queue, which will executed
* with them
*
* in the end a result of the execution of the query-definition
* through the stored handler is returned
*
**/
function get() {
$arrParameter = func_get_args();
if(empty($arrParameter))
throw new \Exception ("no parameter given for execution");
if(!is_string($arrParameter[0]))
throw new UnexpectedParameterTypeException('string', $arrParameter[0]);
# get instance of queue and work with a copy of it
$objQueue = Singleton::getInstance('\DDDBL\Queue');
$objQueue = $objQueue->getClone();
return $objQueue->execute($arrParameter);
}
/**
* @param $strFile - the file with the query definitions to store
*
* store all query-definitions from the given file
*
**/
function storeQueryFileContent($strFile) {
storeDefinitionsFromFileInGroup($strFile, 'Query-Definition');
}
/**
* @param $strDir - the dir with query-definitions files
* @param $strMatch - a rule files in the dir have to match
*
* iterate through all files in the given dir. if a file matches
* the rule in $strMatch, the definitions in the file will be stored
* as query-definitions. all files are match in default.
*
**/
function loadQueryDefinitionsInDir($strDir, $strMatch = '*') {
walkDirForCallback($strDir, '\DDDBL\storeQueryFileContent', $strMatch);
}
/**
* @param $strFile - the file with the database definitions to store
*
* store all database definition from the given file
*
**/
function storeDBFileContent($strFile) {
$cloAdditionalHandler = function ($objDataObjectPool, $arrDefinition) {
if(!empty($arrDefinition['DEFAULT']) && true == (boolean) $arrDefinition['DEFAULT'])
$objDataObjectPool->add('DEFAULT', $arrDefinition);
};
storeDefinitionsFromFileInGroup($strFile, 'Database-Definition', $cloAdditionalHandler);
}
/**
* @param $strDir - the dir with query-definitions files
* @param $strMatch - a rule files in the dir have to match
*
* iterate through all files in the given dir. if a file matches
* the rule in $strMatch, the definitions in the file will be stored
* as database-definitions. all files are matched in default.
*
**/
function loadDBDefinitionsInDir($strDir, $strMatch = '*') {
walkDirForCallback($strDir, '\DDDBL\loadDBDefinitionsInDir', $strMatch);
}
/**
* @param $strPath - the path to the dir to handle
* @param $strCallback - the callback to call when a matching file is found
* @param $strFilenameMatch - the rule to filename has to match
*
* @throws UnexpectedParameterTypeException - if the given path or filematch-rule is not a string
* @throws UnexpectedParameterTypeException - if the given callback is not a callable
* @throws \Exception - if given path is not a directory
* @throws \Exception - if the directory is not readable
*
* reads all files of the given directory (just directory, not recursive)
* and checks, if the filename matches against the given rule. if
* a match is found the given callback is called with the full
* path to the file
*
**/
function walkDirForCallback($strPath, $strCallback, $strFilenameMatch) {
if(!is_string($strPath))
throw new UnexpectedParameterTypeException('string', $strPath);
if(!is_callable($strCallback))
throw new UnexpectedParameterTypeException('callable', $strCallback);
if(!is_string($strFilenameMatch))
throw new UnexpectedParameterTypeException('string', $strFilenameMatch);
if(!is_dir($strPath))
throw new \Exception ('given path is not an directory: ' . $strPath);
$resDirHandle = opendir($strPath);
if(!is_resource($resDirHandle))
throw new \Exception ('could not read directory: ' . $strPath);
while($strFile = readdir($resDirHandle))
if(is_file($strPath.$strFile) && fnmatch($strFilenameMatch, $strFile))
call_user_func_array($strCallback, array($strPath.$strFile));
closedir($resDirHandle);
}
/**
* @param $strFile - the file with definitions
* @param $strGroup - the group the definitions should be stored in
*
* @throws UnexpectedParameterTypeException - if the given file is not a string
* @throws UnexpectedParameterTypeException - if the given optional handler is not a callable
* @throws \Exception - if the given file is not a file or do not exists
* @throws \Exception - if the given file is not readable
*
* generic function to store all definitions in a given file
* in the specified group.
*
* if an additional handler is given, it is called AFTER the storage of the
* definition. when called it will get the reference to the DataObjectPool and the
* found definition as parameter.
*
**/
function storeDefinitionsFromFileInGroup($strFile, $strGroup, $cloAdditionalHandler = null) {
if(!is_string($strGroup))
throw new UnexpectedParameterTypeException('string', $strGroup);
if(!is_null($cloAdditionalHandler) && !is_callable($cloAdditionalHandler))
throw new UnexpectedParameterTypeException('callable', $cloAdditionalHandler);
if(!is_file($strFile) || !file_exists($strFile))
throw new \Exception ("given file is not a file or doesn't exists: $strFile");
if(!is_readable($strFile))
throw new \Exception ("given file is not readable: $strFile");
$arrDefinitions = parse_ini_file($strFile, true);
$objDataObjectPool = new DataObjectPool($strGroup);
foreach($arrDefinitions AS $strDefinitionAlias => $arrDefinition) {
$objDataObjectPool->add($strDefinitionAlias, $arrDefinition);
if(!is_null($cloAdditionalHandler))
$cloAdditionalHandler($objDataObjectPool, $arrDefinition);
}
}

View file

@ -0,0 +1,208 @@
<?php
namespace DDDBL;
$objQueue = Singleton::getInstance('\DDDBL\Queue');
#############################
### db-connection handler ###
#############################
# get (or first establish) connection to database
# and store the DataObject of the connection in the Queue-State
$cloStoreDBConnection = function(\DDDBL\Queue $objQueue, array $arrParameter) {
if(!isConnected())
connect();
$objQueue->getState()->update(array('DB' => getDBDataObject()));
};
$objQueue->addHandler(QUEUE_GET_DB_CONNECTION_POSITION, $cloStoreDBConnection);
###############################
### query-definition-loader ###
###############################
# get the DataObject of the query and store it in the queue
$cloGetQuery = function(\DDDBL\Queue $objQueue, array $arrParameter) {
$objDataObjectPool = new DataObjectPool('Query-Definition');
# get the first entry of the parameter-list; this is the query-alias
$strAlias = array_shift($arrParameter);
if(empty($strAlias) || !is_string($strAlias))
throw new \Exception('no query-alias defined!');
if(!$objDataObjectPool->exists($strAlias))
throw new \Exception("given query alias is unknown: $strAlias");
$objQueue->getState()->update(array('QUERY' => $objDataObjectPool->get($strAlias)));
};
$objQueue->addHandler(QUEUE_GET_QUERY_POSITION, $cloGetQuery);
#################################
### set BIND-DATA-TYPE option ###
#################################
# check if the query has a BIND-DATA-TYPE config.
# if not check if there is one given for the database-connection.
# if yes, store it as setting for the query, otherwise
# set false for this option
$cloSetBindDataTypeConfig = function(\DDDBL\Queue $objQueue, array $arrParameter) {
$objDB = $objQueue->getState()->get('DB');
$objQuery = $objQueue->getState()->get('QUERY');
# skip this step, if the query itselfs has its own
if($objQuery->exists('BIND-DATA-TYPE')) {
$objQuery->update(array('BIND-DATA-TYPE' => (bool) $objQuery->get('BIND-DATA-TYPE'))); #bugfix for php-bug #38409
return;
}
# set type to false, if no config is available, otherwise use the given config
if(!$objDB->exists('BIND-DATA-TYPE'))
$objQuery->update(array('BIND-DATA-TYPE' => false));
else
$objQuery->update(array('BIND-DATA-TYPE' => (bool) $objDB->get('BIND-DATA-TYPE')));
};
$objQueue->addHandler(QUEUE_BIND_DATA_TYPE_POSITION, $cloSetBindDataTypeConfig);
#####################
### prepare query ###
#####################
# get the stored query and prepare() it for the given database-connection
# store the resulting PDOStatement
$cloPrepareQuery = function(\DDDBL\Queue $objQueue, array $arrParameter) {
# if query is not prepared yet, do this now
if(!$objQueue->getState()->get('QUERY')->exists('PDOStatement')) {
$objPDO = $objQueue->getState()->get('DB')->get('PDO');
$objPDO = $objPDO->prepare($objQueue->getState()->get('QUERY')->get('QUERY'));
$objQueue->getState()->get('QUERY')->update(array('PDOStatement' => $objPDO));
}
# copy reference of prepared statement into queue for execution
$objQueue->getState()->update(array('PDOStatement' => $objQueue->getState()->get('QUERY')->get('PDOStatement')));
};
$objQueue->addHandler(QUEUE_PREPARE_QUERY_POSITION, $cloPrepareQuery);
#########################
### execute the query ###
#########################
# handler, which maps the data-type of a variable to the PDO-constants
$cloMapDataType = function($mixedParameter) {
$arrDataTypeMap = array('NULL' => \PDO::PARAM_NULL,
'boolean' => \PDO::PARAM_BOOL,
'integer' => \PDO::PARAM_INT,
'string' => \PDO::PARAM_STR);
$strDataType = gettype($mixedParameter);
if(!isset($arrDataTypeMap[$strDataType]))
throw new \Exception ("could not bind parameters data type - type is not supported by PDO: $strDataType");
return $arrDataTypeMap[$strDataType];
};
# bind the given parameter to the prepared statement,
# then set the fetch mode and execute the query
$cloQueryExcecute = function(\DDDBL\Queue $objQueue, array $arrParameter) use ($cloMapDataType) {
$objPDO = $objQueue->getState()->get('PDOStatement');
# remove the alias from the parameter list
array_shift($arrParameter);
$objQuery = $objQueue->getState()->get('QUERY');
if(true === $objQuery->get('BIND-DATA-TYPE')) {
foreach($arrParameter AS $intIndex => $mixedParameter)
$objPDO->bindValue($intIndex + 1, $mixedParameter, $cloMapDataType($mixedParameter));
} else {
foreach($arrParameter AS $intIndex => $mixedParameter)
$objPDO->bindValue($intIndex + 1, $mixedParameter);
}
$objPDO->setFetchMode(\PDO::FETCH_ASSOC);
# execute the query. if execution fails, throw an exception
if(!$objPDO->execute())
throw new QueryException($objPDO, $objQuery->getAll());
};
$objQueue->addHandler(QUEUE_EXECUTE_QUERY_POSITION, $cloQueryExcecute);
###############################
### format the query result ###
###############################
# if a result-handler for the query is configured, call it
$cloFormatQueryResult = function(\DDDBL\Queue $objQueue, array $arrParameter) {
$objQuery = $objQueue->getState()->get('QUERY');
if(!$objQuery->exists('HANDLER'))
return ;
# get the handler and its config
$strHandlerConfig = $objQuery->get('HANDLER');
$arrHandlerConfig = preg_split('/\s+/', $strHandlerConfig);
$strHandler = array_shift($arrHandlerConfig);
# remove handler-name from config
$strHandlerConfig = trim(str_replace($strHandler, '', $strHandlerConfig));
$objDataObjectPool = new DataObjectPool('Result-Handler');
if(!$objDataObjectPool->exists($strHandler))
throw new \Exception ("unknown result-handler: $strHandler");
$objHandler = $objDataObjectPool->get($strHandler);
$cloHandler = $objHandler->get('HANDLER');
$cloHandler($objQueue, $strHandlerConfig);
};
$objQueue->addHandler(QUEUE_FORMAT_RESULT_POSITION, $cloFormatQueryResult);
####################
### close cursor ###
####################
# closing the cursor of the PDOStatement. this will free
# the result and enable the connection to execute the next query
$cloCloseCursor = function(\DDDBL\Queue $objQueue, array $arrParameter) {
$objQueryResult = $objQueue->getState()->get('PDOStatement');
$objQueryResult->closeCursor();
};
$objQueue->addHandler(QUEUE_CLOSE_CURSOR_POSITION, $cloCloseCursor);

View file

@ -0,0 +1,102 @@
<?php
namespace DDDBL;
$objDataObjectPool = new DataObjectPool('Result-Handler');
#################################
### handler for: SINGLE_VALUE ###
#################################
$cloSingleValueHandler = function(\DDDBL\Queue $objQueue) {
$arrResult = $objQueue->getState()->get('PDOStatement')->fetch();
$objQueue->getState()->update(array('result' => (empty($arrResult)) ? null : reset($arrResult)));
};
$objDataObjectPool->add('SINGLE_VALUE', array('HANDLER' => $cloSingleValueHandler));
###########################
### handler for: SINGLE ###
###########################
$cloSingleHandler = function(\DDDBL\Queue $objQueue) {
$arrResult = $objQueue->getState()->get('PDOStatement')->fetch();
$objQueue->getState()->update(array('result' => (empty($arrResult)) ? null : $arrResult));
};
$objDataObjectPool->add('SINGLE', array('HANDLER' => $cloSingleHandler));
##########################
### handler for: MULTI ###
##########################
$cloMultiHandler = function(\DDDBL\Queue $objQueue) {
$arrResult = $objQueue->getState()->get('PDOStatement')->fetchAll();
$objQueue->getState()->update(array('result' => (empty($arrResult)) ? array() : $arrResult));
};
$objDataObjectPool->add('MULTI', array('HANDLER' => $cloMultiHandler));
#########################
### handler for: LIST ###
#########################
$cloListHandler = function(\DDDBL\Queue $objQueue) {
$objResultCursor = $objQueue->getState()->get('PDOStatement');
$arrResult = array();
while($arrRow = $objResultCursor->fetch())
array_push($arrResult, current($arrRow));
$objQueue->getState()->update(array('result' => $arrResult));
};
$objDataObjectPool->add('LIST', array('HANDLER' => $cloListHandler));
#############################
### handler for: GROUP_BY ###
#############################
$cloGroupedByHandler = function(\DDDBL\Queue $objQueue, $strGroupColumn) {
$objResultCursor = $objQueue->getState()->get('PDOStatement');
$arrResult = array();
while($arrRow = $objResultCursor->fetch()) {
if(!isset($arrRow[$strGroupColumn]))
throw new \Exception ("could not group result by non-existing column: $strGroupColumn");
$arrResult[$arrRow[$strGroupColumn]][] = $arrRow;
}
$objQueue->getState()->update(array('result' => $arrResult));
};
$objDataObjectPool->add('GROUP_BY', array('HANDLER' => $cloGroupedByHandler));
#############################
### handler for: NOT_NULL ###
#############################
$cloNotNullHandler = function(\DDDBL\Queue $objQueue) {
$arrResult = $objQueue->getState()->get('PDOStatement')->fetch();
$objQueue->getState()->update(array('result' => (empty($arrResult)) ? false : true));
};
$objDataObjectPool->add('NOT_NULL', array('HANDLER' => $cloNotNullHandler));

View file

@ -0,0 +1,195 @@
<?php
namespace DDDBL;
/**
* a DataObject is a generic object
* to store data under given keys.
*
* it allows getting, adding, updating and deleting
* data.
*
* a validation callback can be provided
* to ensure, that the stored data
* validate correctly.
*
**/
class DataObject {
/**
* list of stored data
**/
private $arrData = array();
/**
* callback to validate all stored data
**/
private $cloValidator = null;
/**
* @param $cloValidator - optional validator callback to validate stored data
* @param $arrData - optional list of data to store in object
*
* @throws UnexpectedParameterTypeException - if validator callback is not a callable
*
* initiates the data-object and stores the validator callback. if no
* callback is given, a default callback is stored, which validates against
* everything.
*
* if optional data are given, they are passed to DataObject::add(), to be stored
* immediatley
*
**/
public function __construct($cloValidator = null, array $arrData = array()) {
if(!is_null($cloValidator) && !is_callable($cloValidator))
throw new UnexpectedParameterTypeException('callable', $cloValidator);
$this->cloValidator = (!is_null($cloValidator)) ? $cloValidator : function() {return true; };
if(!empty($arrData))
$this->add($arrData);
}
/**
* @param $arrData - list of data to store in object
*
* @throws \Exception - if a key is already in use
* @throws \Exception - if the final data-set do not validate
*
* add the list of data to the existing ones. the given data
* must have the following format:
* array([key] => data
* [key] => data, [..])
*
* if a key in the given data is already used in stored
* data the addition is aborted and an exception is
* thrown.
*
* the stored data are only modified on success
*
**/
public function add(array $arrData) {
$arrMergedData = array_merge($this->arrData, $arrData);
foreach($arrData AS $strKey => $mixData)
if(array_key_exists($strKey, $this->arrData))
throw new \Exception("could not store data, key is already in use: $strKey");
$cloValidator = $this->cloValidator;
if(!$cloValidator($arrMergedData))
throw new \Exception("given data do not validate");
$this->arrData = $arrMergedData;
}
/**
* @param $arrData - list of data to update
*
* @throws \Exception - if the final data-set do not validate
*
* update the stored data with the given data-set. for
* the structure of $arrData have a look at DataObject:add()
*
* existing keys are overwritten with new values. new
* keys are added to the data-set.
*
* if validation of final set fails, an exception is
* thrown. no data are modified on failure.
*
**/
public function update(array $arrData) {
$arrMergedData = array_merge($this->arrData, $arrData);
$cloValidator = $this->cloValidator;
if(!$cloValidator($arrMergedData))
throw new \Exception("given data do not validate");
$this->arrData = $arrMergedData;
}
/**
* @param $strKey - the key of the value to delete
*
* @throws UnexpectedParameterTypeException - if given key is not a string
*
* delete the value stored under the given key.
* if given key do not exists, nothing is done!
*
**/
public function delete($strKey) {
if(!is_string($strKey))
throw new UnexpectedParameterTypeException('string', $strKey);
if($this->exists($strKey))
unset($this->arrData[$strKey]);
}
/**
* @param $strKey - the key to check
*
* @throws UnexpectedParameterTypeException - if given key is not a string
*
* @return (boolean) true, if key exists
* @return (boolean) false, if key do not exists
*
* check if the given key exists
*
**/
public function exists($strKey) {
if(!is_string($strKey))
throw new UnexpectedParameterTypeException('string', $strKey);
if(!array_key_exists($strKey, $this->arrData))
return false;
return true;
}
/**
* @param $strKey - the key to get the value from
*
* @throws UnexpectedParameterTypeException - if given key is not a string
* @throws \Exception - if given key is unknown
*
* @return (mixed) the value stored under the given key
*
* return the value stored under the given key
*
**/
public function get($strKey) {
if(!is_string($strKey))
throw new UnexpectedParameterTypeException('string', $strKey);
if(!$this->exists($strKey))
throw new \Exception("unknown key: $strKey");
return $this->arrData[$strKey];
}
/**
* return all stored data in the structure of:
* array([key] => data
* [key] => data, [..])
*
**/
public function getAll() {
return $this->arrData;
}
}

View file

@ -0,0 +1,207 @@
<?php
namespace DDDBL;
/**
* The DataObjectPool is a class to manage
* the DataObjects for different types.
*
* DataObjects are stored within groups. Every group
* has a validatator, with is applyed to
* every DataObject stored in the group.
* If no validatator is set, no validation will
* be done.
*
* A DataObject is referenced by an identifier,
* which is uniqiue within a group.
*
* when creating a DataObjectPool instance,
* the wanted group is set. All following
* operations are done at this group.
*
**/
class DataObjectPool {
/**
* the actual group to operate on
*
**/
private $strGroup = null;
/**
* list of validators for each group. structure:
* array([group] => validator-callback,
* [group-n] => validator-callback-n, [..])
*
**/
static private $arrValidatorList = array();
/**
* list of DataObjects. stored in the following structure:
* array([group][uniqueue-identifier] => DataObject-reference,
* [group-n][uniqueue-identifier-n] => DataObject-reference-n, [..])
*
**/
static private $arrDataObjects = array();
/**
* @param $strGroup - the group of DataObjects to operate on
*
* @throws UnexpectedParameterTypeException - if given group is not a string
*
* create an instance of DataObjectPool and store the group
* to operate on
*
**/
public function __construct($strGroup) {
if(!is_string($strGroup))
throw new UnexpectedParameterTypeException('string', $strGroup);
$this->strGroup = $strGroup;
if(!array_key_exists($this->strGroup, self::$arrValidatorList))
self::$arrValidatorList[$this->strGroup] = null;
if(!array_key_exists($this->strGroup, self::$arrDataObjects))
self::$arrDataObjects[$this->strGroup] = array();
}
/**
* @param $cloValidator - the validator to set for the group
*
* @throws UnexpectedParameterTypeException - if given validator is not a callable
*
* set the validator for the active group. this validator
* is given to each newly created DataObject.
* if it is changed, the existing DataObjects are
* *NOT* revalidated.
*
**/
public function setValidator($cloValidator) {
if(!is_callable($cloValidator))
throw new UnexpectedParameterTypeException('string', $cloValidator);
self::$arrValidatorList[$this->strGroup] = $cloValidator;
}
/**
* @param $strIdentifier - the unique identifier of the DataObject
* @param $arrData - the data to store in the DataObject
*
* @see DataObject:add()
*
* @throws UnexpectedParameterTypeException - if identifier is not a string
* @throws \Exception - if given identifier is not unique
*
* @returns (DataObject) - reference to the created DataObject-instance
*
* create a new DataObject and store it in the pool. The given
* identifier is the key to retrieve the DataObject from the pool.
* The given data are stored within the DataObject.
*
* After creation and storage of the DataObject, a reference
* to the object is returned
*
**/
public function add($strIdentifier, array $arrData) {
if(!is_string($strIdentifier))
throw new UnexpectedParameterTypeException('string', $strIdentifier);
if($this->exists($strIdentifier))
throw new \Exception ("identifier already in use: $strIdentifier");
$objDataObject = new DataObject(self::$arrValidatorList[$this->strGroup], $arrData);
self::$arrDataObjects[$this->strGroup][$strIdentifier] = $objDataObject;
return $objDataObject;
}
/**
* @param $strIdentifier - the identifier of the object to delete
*
* @throws UnexpectedParameterTypeException - if given identifier is not a string
* @throws \Exception - if the given identifier is not known
*
* delete the stored DataObject from the DataObjectPool
*
**/
public function delete($strIdentifier) {
if(!is_string($strIdentifier))
throw new UnexpectedParameterTypeException('string', $strIdentifier);
if(!$this->exists($strIdentifier))
throw new \Exception ("DataObject not found, identifier unknown: $strIdentifier");
unset(self::$arrDataObjects[$this->strGroup][$strIdentifier]);
}
/**
* @param $strIdentifier - the identifier to check
*
* @throws UnexpectedParameterTypeException - if given identifier is not a string
*
* @returns (boolean) true, if the identifier exists
* @returns (boolean) false, if the identifier do not exists
*
**/
public function exists($strIdentifier) {
if(!is_string($strIdentifier))
throw new UnexpectedParameterTypeException('string', $strIdentifier);
if(!isset(self::$arrDataObjects[$this->strGroup][$strIdentifier]))
return false;
return true;
}
/**
* @param $strIdentifier - the identifier of the DataObject to retrieve
*
* @throws UnexpectedParameterTypeException - if given identifier is not a string
* @throws \Exception - if given identifier is unknown
*
* @returns (DataObject) - reference to the DataObject
*
* returns a reference to the DataObject stored under the identifer
*
**/
public function get($strIdentifier) {
if(!is_string($strIdentifier))
throw new UnexpectedParameterTypeException('string', $strIdentifier);
if(!$this->exists($strIdentifier))
throw new \Exception ("DataObject not found, identifier unknown: $strIdentifier");
return self::$arrDataObjects[$this->strGroup][$strIdentifier];
}
/**
* @returns (array) - list of all DataObjects of the active group
*
* returns an array of all stored DataObjects of the active group
* with the following structure:
*
* array([identifier] => DataObject-reference,
* [identifier-n] => DataObject-reference-n, [..])
*
**/
public function getAll() {
return self::$arrDataObjects[$this->strGroup];
}
}

View file

@ -0,0 +1,138 @@
<?php
namespace DDDBL;
/**
* this class implements a queue of handler, which
* are called in a specified order.
*
* this allows the combiniation of different steps,
* like database-connection management, query execution
* and result parsing in a simple list of actions.
*
* Queue::getClone() returns a clone of the queue,
* which allows modifications of the queue by
* the executed handler.
* in this way different problems, like substituions,
* test-cases, statistics and much more can be solved,
* without destroying the configured order for other queries.
*
**/
class Queue {
/**
* the sorted (!) queue of handler to execute
*
**/
private $arrHandlerQueue = array();
/**
* @see \DDDBL\DataObject
*
* an DataObject, which is used to store the states of the queue
*
**/
private $objState = null;
/**
* @param $intPosition - the position to store the handler at
* @param $cloHandler - the handler to store in the queue
*
* @throws UnexpectedParameterTypeException - if the first parameter is not an integer
* @throws UnexpectedParameterTypeException - if the second parameter is not a callable
* @throws \Exception - if there is already a handler stored under the given position
*
* store the given handler under the given position in the queue.
* if the position is already in use an expection is thrown.
*
**/
public function addHandler($intPosition, $cloHandler) {
if(!is_int($intPosition))
throw new UnexpectedParameterTypeException('integer', $intPosition);
if(!is_callable($cloHandler))
throw new UnexpectedParameterTypeException('callable', $cloHandler);
if(!empty($this->arrHandlerQueue[$intPosition]))
throw new \Exception("there is already a handler stored for position: $intPosition");
$this->arrHandlerQueue[$intPosition] = $cloHandler;
ksort($this->arrHandlerQueue);
}
/**
* @param $intPosition - the position the handler for deletion is stored under
*
* @throws UnexpectedParameterTypeException - if the parameter is not an integer
*
* delete the handler stored under the given position
*
**/
public function deleteHandler($intPosition) {
if(!is_int($intPosition))
throw new UnexpectedParameterTypeException('integer', $intPosition);
if(array_key_exists($intPosition, $this->arrHandlerQueue))
unset($this->arrHandlerQueue[$intPosition]);
}
/**
* @returns (\DDDBL\Queue) - a clone of the queue-instance
*
* return a clone of the acutal queue
*
**/
public function getClone() {
return clone $this;
}
/**
* @param $arrParameter - the parameter to use when executing the queue-handler
*
* @returns (mixed) the state of "result"
*
* execute all handler in the queue, in the given
* order from low to high. after execution return the
* state "result".
*
* handler which generates an output
* are expected to store the result in this state
*
**/
public function execute(array $arrParameter) {
$this->getState()->add(array('result' => null));
foreach($this->arrHandlerQueue AS $cloHandler)
$cloHandler($this, $arrParameter);
return $this->getState()->get('result');
}
/**
* @returns (DataObject) - the DataObject which handles the states of the queue
*
* returns a reference to the DataObject, which
* stores all states of the queue.
*
* if no object exists till now, a new one is created
*
**/
public function getState() {
if(!is_object($this->objState))
$this->objState = new DataObject();
return $this->objState;
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace DDDBL;
/**
* simple implementation of generic singleton
* for all classes, which allows additional instances
* if needed
*
**/
class Singleton {
/**
* @param $strClass - the class we want an instance from
*
* @throws UnexpectedParameterTypeException - if given parameter is not a string
* @throws \Exception - if given class do not exists
*
* @return (object) - an instance of the given classname
*
* get a reference to the instance of the given class.
* if instance do not exists, create one. after creation
* always return reference to this reference
*
**/
static function getInstance($strClass) {
if(!is_string($strClass))
throw new UnexpectedParameterTypeException('string', $strClass);
if(!class_exists($strClass))
throw new \Exception ("class do not exists: $strClass");
static $arrObjectList = array();
if(!isset($arrObjectList[$strClass]))
$arrObjectList[$strClass] = new $strClass();
return $arrObjectList[$strClass];
}
}

View file

@ -0,0 +1,206 @@
<?php
namespace DDDBL;
/**
* @returns (PDO) - reference to PDO object
* @returns (boolean) false, if there is no connection to the database
*
* if there is a connection to the database,
* the PDO object is returned otherwise false
*
**/
function getDB() {
if(!isConnected())
return false;
$objDB = getDBDataObject();
return $objDB->get('PDO');
}
/**
* @returns (boolean) true, if connection exists or is established
* @returns (boolean) false, if connection could not be established
*
* if no connection to the database exists, establishe one.
*
**/
function connect() {
if(isConnected())
return true;
$objDB = getDBDataObject();
try {
$objPDO = new \PDO($objDB->get('CONNECTION'),
$objDB->get('USER'),
$objDB->get('PASS'));
} catch (\Exception $objException) {
return false;
}
$objDB->update(array('PDO' => $objPDO));
return true;
}
/**
* disconnect from the database
*
**/
function disconnect() {
$objDB = getDBDataObject();
$objPDO = $objDB->get('PDO');
$objPDO = null;
$objDB->delete('PDO');
}
/**
* check if a connection to the database is established
*
**/
function isConnected() {
$objDB = getDBDataObject();
if(!$objDB->exists('PDO'))
return false;
return true;
}
/**
* @returns (boolean) true, if transaction started
* @returns (boolean) false, if transaction could not be started
* @returns (boolean) false, if no connection to database exists
*
* start a transaction
*
**/
function startTransaction() {
return mapMethod('beginTransaction');
}
/**
* @returns (boolean) true, if there is an active transaction
* @returns (boolean) false, if there is no active transaction
* @returns (boolean) false, if no connection to database exists
*
* check if there is an active transaction
*
**/
function inTransaction() {
return mapMethod('inTransaction');
}
/**
* @returns (boolean) true, if rollback was successfull
* @returns (boolean) false, if rollback was not successfull
* @returns (boolean) false, if no connection to database exists
*
* perform a rollback of the active transaction
*
**/
function rollback() {
return mapMethod('rollback');
}
/**
* @returns (boolean) true, if commit was successfull
* @returns (boolean) false, if commit was not successfull
* @returns (boolean) false, if no connection to database exists
*
* commit the active transaction
*
**/
function commit() {
return mapMethod('commit');
}
/**
* @returns (array) - list of error-information
*
* get information about an error
*
**/
function getErrorInfo() {
return mapMethod('errorInfo');
}
/**
* change the active database-connection. all db-functions
* are performed at the new connection.
*
* ATTENTION: the old connection is *not* closed!
*
**/
function changeDB($strIdentifier) {
$objDataObjectPool = new DataObjectPool('Database-Definition');
$objNewDB = $objDataObjectPool->get($strIdentifier);
$objDataObjectPool->delete('DEFAULT');
$objDataObjectPool->add('DEFAULT', $objNewDB->getAll());
}
/**
* @returns (DataObject) - reference to the DataObject of default connection
*
* returns the DataObject of the default connection.
*
**/
function getDBDataObject() {
$objDataObjectPool = new DataObjectPool('Database-Definition');
return $objDataObjectPool->get('DEFAULT');
}
/**
* @throws UnexpectedParameterTypeException - if the given parameter is not a string
*
* @returns (boolean) false, if no connection is established
*
* check if a connection to the database is established. if so,
* the given parameter is used, as method to call at the
* PDO object. the result of the call is returned
*
**/
function mapMethod($strMethod) {
if(!is_string($strMethod))
throw new UnexpectedParameterTypeException('string', $strMethod);
if(!isConnected())
return false;
$objDB = getDBDataObject();
$objPDO = $objDB->get('PDO');
return $objPDO->$strMethod();
}

View file

@ -0,0 +1,94 @@
<?php
namespace DDDBL;
/**
*
* create an exception with relevant information, if a query fails
*
**/
class QueryException extends \Exception {
/**
*
* @param $objPDO - the PDO object which caused the error when executed
* @param $arrQueryDefinition - the complete query definition
*
* create an error message which contains all relevant informations
* and print them as exception
*
**/
public function __construct(\PDOStatement $objPDO, $arrQueryDefinition) {
$strMessage = self::createErrorMessage($objPDO, $arrQueryDefinition);
parent::__construct($strMessage);
}
/**
*
* @param $objPDO - the PDO object related with the error
* @param $arrQueryDefinition - the complete query definition
*
* @return (string) the complete exception message
*
* build and return the exception message out of the given error info
* and query definition
*
**/
private function createErrorMessage($objPDO, $arrQueryDefinition) {
$strMessage = self::flattenQueryErrorInfo($objPDO);
$strMessage .= self::flattenQueryDefiniton($arrQueryDefinition);
return $strMessage;
}
/**
*
* @param $objPDO - PDO object to get error information from
*
* @return (string) a flatten error info from the query object
*
* build and return a flatten error-info
* from the driver specific error message
*
**/
private function flattenQueryErrorInfo($objPDO) {
$arrErrorInfo = $objPDO->errorInfo();
$strMessage = '';
if(!empty($arrErrorInfo) && !empty($arrErrorInfo[0]) && '00000' !== $arrErrorInfo[0])
$strMessage = "\nError-Code: {$arrErrorInfo[0]}\nError-Message: {$arrErrorInfo[2]}\n";
return $strMessage;
}
/**
*
* @param $arrQueryDefinition - the complete query definition
*
* @return (string) a text version of the query definition
*
* create an text, which contains all information
* of the query definition
*
**/
private function flattenQueryDefiniton($arrQueryDefinition) {
$strMessage = "\nQuery-Definiton:\n";
foreach($arrQueryDefinition AS $strKeyword => $strContent)
$strMessage .= "$strKeyword: $strContent\n";
return $strMessage . "\n";
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace DDDBL;
/**
* exception if the given parameter
* has an unexpected data-type
*
**/
class UnexpectedParameterTypeException extends \Exception {
/**
* @param $strExpected - the expected datatype
* @param $mixedValue - the given parameter
*
* determines the datatype of the given parameter and
* creates and stores the exception message
*
**/
public function __construct($strExpected, $mixedValue) {
parent::__construct("value of type $strExpected expected, but got: " . gettype($mixedValue));
}
}

View file

@ -87,10 +87,11 @@ function admin_content(&$a) {
if(x($_SESSION,'submanage') && intval($_SESSION['submanage']))
return "";
if (function_exists("apc_delete")) {
$toDelete = new APCIterator('user', APC_ITER_VALUE);
apc_delete($toDelete);
}
// APC deactivated, since there are problems with PHP 5.5
//if (function_exists("apc_delete")) {
// $toDelete = new APCIterator('user', APC_ITER_VALUE);
// apc_delete($toDelete);
//}
/**
* Side bar links
@ -329,7 +330,7 @@ function admin_page_site_post(&$a){
$private_addons = ((x($_POST,'private_addons')) ? True : False);
$disable_embedded = ((x($_POST,'disable_embedded')) ? True : False);
$allow_users_remote_self = ((x($_POST,'allow_users_remote_self')) ? True : False);
$no_multi_reg = ((x($_POST,'no_multi_reg')) ? True : False);
$no_openid = !((x($_POST,'no_openid')) ? True : False);
$no_regfullname = !((x($_POST,'no_regfullname')) ? True : False);
@ -1029,13 +1030,24 @@ function admin_page_plugins(&$a){
*/
$plugins = array();
$files = glob("addon/*/");
$files = glob("addon/*/"); /* */
if($files) {
foreach($files as $file) {
foreach($files as $file) {
if (is_dir($file)){
list($tmp, $id)=array_map("trim", explode("/",$file));
$info = get_plugin_info($id);
$plugins[] = array( $id, (in_array($id, $a->plugins)?"on":"off") , $info);
$show_plugin = true;
// If the addon is unsupported, then only show it, when it is enabled
if ((strtolower($info["status"]) == "unsupported") AND !in_array($id, $a->plugins))
$show_plugin = false;
// Override the above szenario, when the admin really wants to see outdated stuff
if (get_config("system", "show_unsupported_addons"))
$show_plugin = true;
if ($show_plugin)
$plugins[] = array($id, (in_array($id, $a->plugins)?"on":"off") , $info);
}
}
}
@ -1046,7 +1058,7 @@ function admin_page_plugins(&$a){
'$page' => t('Plugins'),
'$submit' => t('Save Settings'),
'$baseurl' => $a->get_baseurl(true),
'$function' => 'plugins',
'$function' => 'plugins',
'$plugins' => $plugins,
'$form_security_token' => get_form_security_token("admin_themes"),
));
@ -1128,16 +1140,16 @@ function admin_page_themes(&$a){
$allowed_themes[] = trim($x);
$themes = array();
$files = glob('view/theme/*');
if($files) {
foreach($files as $file) {
$f = basename($file);
$is_experimental = intval(file_exists($file . '/experimental'));
$files = glob('view/theme/*'); /* */
if($files) {
foreach($files as $file) {
$f = basename($file);
$is_experimental = intval(file_exists($file . '/experimental'));
$is_supported = 1-(intval(file_exists($file . '/unsupported'))); // Is not used yet
$is_allowed = intval(in_array($f,$allowed_themes));
$themes[] = array('name' => $f, 'experimental' => $is_experimental, 'supported' => $is_supported, 'allowed' => $is_allowed);
}
}
}
}
if(! count($themes)) {
notice( t('No themes found.'));
@ -1273,12 +1285,12 @@ function admin_page_logs_post(&$a) {
set_config('system','debugging', $debugging);
set_config('system','loglevel', $loglevel);
}
info( t("Log settings updated.") );
goaway($a->get_baseurl(true) . '/admin/logs' );
return; // NOTREACHED
return; // NOTREACHED
}
/**
@ -1286,7 +1298,7 @@ function admin_page_logs_post(&$a) {
* @return string
*/
function admin_page_logs(&$a){
$log_choices = Array(
LOGGER_NORMAL => 'Normal',
LOGGER_TRACE => 'Trace',
@ -1294,7 +1306,7 @@ function admin_page_logs(&$a){
LOGGER_DATA => 'Data',
LOGGER_ALL => 'All'
);
$t = get_markup_template("admin_logs.tpl");
$f = get_config('system','logfile');
@ -1326,7 +1338,7 @@ readable.");
}
fclose($fp);
}
}
}
return replace_macros($t, array(
'$title' => t('Administration'),
@ -1336,7 +1348,7 @@ readable.");
'$data' => $data,
'$baseurl' => $a->get_baseurl(true),
'$logname' => get_config('system','logfile'),
// name, label, value, help string, extra data...
'$debugging' => array('debugging', t("Enable Debugging"),get_config('system','debugging'), ""),
'$logfile' => array('logfile', t("Log file"), get_config('system','logfile'), t("Must be writable by web server. Relative to your Friendica top-level directory.")),
@ -1355,7 +1367,7 @@ function admin_page_remoteupdate_post(&$a) {
return;
}
if (x($_POST,'remotefile') && $_POST['remotefile']!=""){
$remotefile = $_POST['remotefile'];
$ftpdata = (x($_POST['ftphost'])?$_POST:false);
@ -1378,14 +1390,14 @@ function admin_page_remoteupdate(&$a) {
$canwrite = canWeWrite();
$canftp = function_exists('ftp_connect');
$needupdate = true;
$u = checkUpdate();
if (!is_array($u)){
$needupdate = false;
$u = array('','','');
}
$tpl = get_markup_template("admin_remoteupdate.tpl");
return replace_macros($tpl, array(
'$baseurl' => $a->get_baseurl(true),
@ -1402,5 +1414,5 @@ function admin_page_remoteupdate(&$a) {
'$ftppwd' => array('ftppwd', t("FTP Password"), '',''),
'$remotefile'=>array('remotefile','', $u['2'],''),
));
}

View file

@ -738,7 +738,7 @@ die("ss");
// This problem can occur expecially with imported facebook posts
$max_comments = get_config("system", "max_comments");
if ($max_comments == 0)
$max_comments = 1000;
$max_comments = 100;
$items = array();

View file

@ -51,6 +51,7 @@ function completeurl($url, $scheme) {
}
function parseurl_getsiteinfo($url, $no_guessing = false) {
$siteinfo = array();
$url = trim($url, "'");
@ -172,7 +173,7 @@ function parseurl_getsiteinfo($url, $no_guessing = false) {
$siteinfo["image"] = $attr["content"];
break;
case "twitter:card":
if ($siteinfo["type"] == "")
if (($siteinfo["type"] == "") OR ($attr["content"] == "photo"))
$siteinfo["type"] = $attr["content"];
break;
case "twitter:description":
@ -440,3 +441,4 @@ function parse_url_content(&$a) {
killme();
}
?>

View file

@ -27,8 +27,6 @@ function removeme_post(&$a) {
}
function removeme_content(&$a) {
if(! local_user())
@ -36,6 +34,9 @@ function removeme_content(&$a) {
$hash = random_string();
require_once("mod/settings.php");
settings_init($a);
$_SESSION['remove_account_verify'] = $hash;
$tpl = get_markup_template('removeme.tpl');
@ -48,6 +49,6 @@ function removeme_content(&$a) {
'$submit' => t('Remove My Account')
));
return $o;
return $o;
}
}

View file

@ -16,10 +16,11 @@ function get_theme_config_file($theme){
function settings_init(&$a) {
if (function_exists("apc_delete")) {
$toDelete = new APCIterator('user', APC_ITER_VALUE);
apc_delete($toDelete);
}
// APC deactivated, since there are problems with PHP 5.5
//if (function_exists("apc_delete")) {
// $toDelete = new APCIterator('user', APC_ITER_VALUE);
// apc_delete($toDelete);
//}
// These lines provide the javascript needed by the acl selector
@ -956,6 +957,8 @@ function settings_content(&$a) {
$pageset_tpl = get_markup_template('pagetypes.tpl');
$pagetype = replace_macros($pageset_tpl, array(
'$user' => t("User Types"),
'$community' => t("Community Types"),
'$page_normal' => array('page-flags', t('Normal Account Page'), PAGE_NORMAL,
t('This account is a normal personal profile'),
($a->user['page-flags'] == PAGE_NORMAL)),

View file

@ -0,0 +1,32 @@
Dear {{$username}},
the administrator of {{$sitename}} has set up an account for you.
The login details are as follows:
Site Location: {{$siteurl}}
Login Name: {{$email}}
Password: {{$password}}
You may change your password from your account "Settings" page after logging
in.
Please take a few moments to review the other account settings on that page.
You may also wish to add some basic information to your default profile
(on the "Profiles" page) so that other people can easily find you.
We recommend setting your full name, adding a profile photo,
adding some profile "keywords" (very useful in making new friends) - and
perhaps what country you live in; if you do not wish to be more specific
than that.
We fully respect your right to privacy, and none of these items are necessary.
If you are new and do not know anybody here, they may help
you to make some new and interesting friends.
Thank you and welcome to {{$sitename}}.
Sincerely,
{{$sitename}} Administrator

View file

@ -62,3 +62,42 @@ span.connector {
.type-link img + br, .type-video img + br{
display: none;
}
/* Shared Messages */
.shared_header {
height: 32px;
color: #999;
border-top: 1px solid #D2D2D2;
padding-top: 5px;
margin-top: 5px;
}
.shared_header a {
color: black;
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
-ms-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
}
.shared_header a:hover {
color: #36c;
}
.shared_header img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
}
.shared_header span {
margin-left: 9px;
}
blockquote.shared_content {
margin-left: 32px;
color: #000;
border: none;
}

View file

@ -3,8 +3,10 @@
* DO NOT EDIT THIS FILE, CHANGES WILL BE OVERWRITTEN
*
*}}
<h4>{{$user}}</h4>
{{include file="field_radio.tpl" field=$page_normal}}
{{include file="field_radio.tpl" field=$page_community}}
{{include file="field_radio.tpl" field=$page_prvgroup}}
{{include file="field_radio.tpl" field=$page_soapbox}}
{{include file="field_radio.tpl" field=$page_freelove}}
<h4>{{$community}}</h4>
{{include file="field_radio.tpl" field=$page_community}}
{{include file="field_radio.tpl" field=$page_prvgroup}}

View file

@ -0,0 +1 @@
{{* Dummy file to avoid errors when installing themes *}}

View file

@ -233,44 +233,6 @@ div.pager {
float: left;
}
.shared_header {
height: 32px;
color: #999;
border-top: 1px solid #D2D2D2;
padding-top: 5px;
margin-top: 5px;
}
.shared_header a {
color: black;
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
-ms-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
}
.shared_header a:hover {
color: #36c;
}
.shared_header img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
}
.shared_header span {
margin-left: 9px;
}
blockquote.shared_content {
margin-left: 32px;
color: #000;
border: none;
}
#contact-edit-drop-link-end {
/* clear: both; */
}
@ -953,7 +915,7 @@ aside #profiles-menu {
}
aside #search-text, aside #side-follow-url, aside #side-peoplefind-url {
width: 150px;
width: 140px;
height: 17px;
padding-left: 10px;
/*border-top-left-radius: 15px;