Merge pull request #3813 from annando/remove-old-stuff
Removed stuff that was never used or isn't used anymore
This commit is contained in:
commit
476d7d9533
|
@ -1,356 +0,0 @@
|
|||
<?php
|
||||
|
||||
use DDDBL\DataObjectPool;
|
||||
use DDDBL\Queue;
|
||||
|
||||
require_once('include/datetime.php');
|
||||
|
||||
$objDDDBLResultHandler = new 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(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));
|
||||
|
||||
if (! class_exists('dba')) {
|
||||
/**
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
class dba {
|
||||
|
||||
private $debug = 0;
|
||||
private $db;
|
||||
private $result;
|
||||
public $connected = false;
|
||||
public $error = false;
|
||||
|
||||
function __construct($server,$user,$pass,$db,$install = false) {
|
||||
$a = get_app();
|
||||
|
||||
// work around, to store the database - configuration in DDDBL
|
||||
$objDataObjectPool = new 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 && 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Establish 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) {
|
||||
$a = get_app();
|
||||
|
||||
$strHandler = (true === $onlyquery) ? 'PDOStatement' : 'MULTI';
|
||||
|
||||
$strQueryAlias = md5($sql);
|
||||
$strSQLType = strtoupper(strstr($sql, ' ', true));
|
||||
|
||||
$objPreparedQueryPool = new 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;
|
||||
}
|
||||
$intErrorCode = false;
|
||||
} catch (Exception $objException) {
|
||||
$result = false;
|
||||
$intErrorCode = $objPreparedQueryPool->get($strQueryAlias)->get('PDOStatement')->errorCode();
|
||||
}
|
||||
|
||||
$stamp2 = microtime(true);
|
||||
$duration = (float)($stamp2-$stamp1);
|
||||
|
||||
$a->save_timestamp($stamp1, "database");
|
||||
|
||||
/*
|
||||
* Check if the configuration group 'system' and db_log is there. The
|
||||
* extra first check needs to be done to avoid endless loop.
|
||||
*/
|
||||
if (x($a->config, 'system') && x($a->config['system'], 'db_log') && ($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 {
|
||||
/// @TODO 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 (isset($result) && ($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 (isset($result) && (($result === true) || ($result === false))) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($onlyquery) {
|
||||
// this will store an PDOStatement Object in result
|
||||
$this->result = $r;
|
||||
|
||||
// execute the Statement, to get its result
|
||||
$this->result->execute();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public 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);
|
||||
}
|
||||
}}
|
||||
|
||||
if (! function_exists('q')) {
|
||||
/*
|
||||
* Function: q($sql,$args);
|
||||
* Description: execute SQL query with printf style args.
|
||||
* Example: $r = q("SELECT * FROM `%s` WHERE `uid` = %d",
|
||||
* 'user', 1);
|
||||
*/
|
||||
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;
|
||||
}}
|
||||
|
||||
if (! function_exists('dbq')) {
|
||||
/*
|
||||
* Raw db query, no arguments
|
||||
*/
|
||||
function dbq($sql) {
|
||||
global $db;
|
||||
if ($db && $db->connected) {
|
||||
$ret = $db->q($sql);
|
||||
} else {
|
||||
$ret = false;
|
||||
}
|
||||
return $ret;
|
||||
}}
|
||||
|
||||
if (! function_exists('dbesc_array_cb')) {
|
||||
function dbesc_array_cb(&$item, $key) {
|
||||
/*
|
||||
* 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 (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);
|
||||
}}
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
// warning: this file is encoded in UTF-8!
|
||||
|
||||
class HTML5_Data
|
||||
{
|
||||
|
||||
// at some point this should be moved to a .ser file. Another
|
||||
// possible optimization is to give UTF-8 bytes, not Unicode
|
||||
// codepoints
|
||||
protected static $realCodepointTable = array(
|
||||
0x0D => 0x000A, // LINE FEED (LF)
|
||||
0x80 => 0x20AC, // EURO SIGN ('€')
|
||||
0x81 => 0xFFFD, // REPLACEMENT CHARACTER
|
||||
0x82 => 0x201A, // SINGLE LOW-9 QUOTATION MARK ('‚')
|
||||
0x83 => 0x0192, // LATIN SMALL LETTER F WITH HOOK ('ƒ')
|
||||
0x84 => 0x201E, // DOUBLE LOW-9 QUOTATION MARK ('„')
|
||||
0x85 => 0x2026, // HORIZONTAL ELLIPSIS ('…')
|
||||
0x86 => 0x2020, // DAGGER ('†')
|
||||
0x87 => 0x2021, // DOUBLE DAGGER ('‡')
|
||||
0x88 => 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT ('ˆ')
|
||||
0x89 => 0x2030, // PER MILLE SIGN ('‰')
|
||||
0x8A => 0x0160, // LATIN CAPITAL LETTER S WITH CARON ('Š')
|
||||
0x8B => 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK ('‹')
|
||||
0x8C => 0x0152, // LATIN CAPITAL LIGATURE OE ('Œ')
|
||||
0x8D => 0xFFFD, // REPLACEMENT CHARACTER
|
||||
0x8E => 0x017D, // LATIN CAPITAL LETTER Z WITH CARON ('Ž')
|
||||
0x8F => 0xFFFD, // REPLACEMENT CHARACTER
|
||||
0x90 => 0xFFFD, // REPLACEMENT CHARACTER
|
||||
0x91 => 0x2018, // LEFT SINGLE QUOTATION MARK ('‘')
|
||||
0x92 => 0x2019, // RIGHT SINGLE QUOTATION MARK ('’')
|
||||
0x93 => 0x201C, // LEFT DOUBLE QUOTATION MARK ('“')
|
||||
0x94 => 0x201D, // RIGHT DOUBLE QUOTATION MARK ('”')
|
||||
0x95 => 0x2022, // BULLET ('•')
|
||||
0x96 => 0x2013, // EN DASH ('–')
|
||||
0x97 => 0x2014, // EM DASH ('—')
|
||||
0x98 => 0x02DC, // SMALL TILDE ('˜')
|
||||
0x99 => 0x2122, // TRADE MARK SIGN ('™')
|
||||
0x9A => 0x0161, // LATIN SMALL LETTER S WITH CARON ('š')
|
||||
0x9B => 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK ('›')
|
||||
0x9C => 0x0153, // LATIN SMALL LIGATURE OE ('œ')
|
||||
0x9D => 0xFFFD, // REPLACEMENT CHARACTER
|
||||
0x9E => 0x017E, // LATIN SMALL LETTER Z WITH CARON ('ž')
|
||||
0x9F => 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS ('Ÿ')
|
||||
);
|
||||
|
||||
protected static $namedCharacterReferences;
|
||||
|
||||
protected static $namedCharacterReferenceMaxLength;
|
||||
|
||||
/**
|
||||
* Returns the "real" Unicode codepoint of a malformed character
|
||||
* reference.
|
||||
*/
|
||||
public static function getRealCodepoint($ref) {
|
||||
if (!isset(self::$realCodepointTable[$ref])) return false;
|
||||
else return self::$realCodepointTable[$ref];
|
||||
}
|
||||
|
||||
public static function getNamedCharacterReferences() {
|
||||
if (!self::$namedCharacterReferences) {
|
||||
self::$namedCharacterReferences = unserialize(
|
||||
file_get_contents(dirname(__FILE__) . '/named-character-references.ser'));
|
||||
}
|
||||
return self::$namedCharacterReferences;
|
||||
}
|
||||
|
||||
public static function getNamedCharacterReferenceMaxLength() {
|
||||
if (!self::$namedCharacterReferenceMaxLength) {
|
||||
$namedCharacterReferences = self::getNamedCharacterReferences();
|
||||
$lengths = array_map('strlen', array_keys($namedCharacterReferences));
|
||||
self::$namedCharacterReferenceMaxLength = max($lengths);
|
||||
}
|
||||
return self::$namedCharacterReferenceMaxLength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a Unicode codepoint to sequence of UTF-8 bytes.
|
||||
* @note Shamelessly stolen from HTML Purifier, which is also
|
||||
* shamelessly stolen from Feyd (which is in public domain).
|
||||
*/
|
||||
public static function utf8chr($code) {
|
||||
if($code > 0x10FFFF or $code < 0x0 or
|
||||
($code >= 0xD800 and $code <= 0xDFFF) ) {
|
||||
// bits are set outside the "valid" range as defined
|
||||
// by UNICODE 4.1.0
|
||||
return "\xEF\xBF\xBD";
|
||||
}
|
||||
|
||||
$x = $y = $z = $w = 0;
|
||||
if ($code < 0x80) {
|
||||
// regular ASCII character
|
||||
$x = $code;
|
||||
} else {
|
||||
// set up bits for UTF-8
|
||||
$x = ($code & 0x3F) | 0x80;
|
||||
if ($code < 0x800) {
|
||||
$y = (($code & 0x7FF) >> 6) | 0xC0;
|
||||
} else {
|
||||
$y = (($code & 0xFC0) >> 6) | 0x80;
|
||||
if($code < 0x10000) {
|
||||
$z = (($code >> 12) & 0x0F) | 0xE0;
|
||||
} else {
|
||||
$z = (($code >> 12) & 0x3F) | 0x80;
|
||||
$w = (($code >> 18) & 0x07) | 0xF0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// set up the actual character
|
||||
$ret = '';
|
||||
if($w) $ret .= chr($w);
|
||||
if($z) $ret .= chr($z);
|
||||
if($y) $ret .= chr($y);
|
||||
$ret .= chr($x);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,284 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2009 Geoffrey Sneddon <http://gsnedders.com/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Some conventions:
|
||||
// /* */ indicates verbatim text from the HTML 5 specification
|
||||
// // indicates regular comments
|
||||
|
||||
class HTML5_InputStream {
|
||||
/**
|
||||
* The string data we're parsing.
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* The current integer byte position we are in $data
|
||||
*/
|
||||
private $char;
|
||||
|
||||
/**
|
||||
* Length of $data; when $char === $data, we are at the end-of-file.
|
||||
*/
|
||||
private $EOF;
|
||||
|
||||
/**
|
||||
* Parse errors.
|
||||
*/
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* @param $data Data to parse
|
||||
*/
|
||||
public function __construct($data) {
|
||||
|
||||
/* Given an encoding, the bytes in the input stream must be
|
||||
converted to Unicode characters for the tokeniser, as
|
||||
described by the rules for that encoding, except that the
|
||||
leading U+FEFF BYTE ORDER MARK character, if any, must not
|
||||
be stripped by the encoding layer (it is stripped by the rule below).
|
||||
|
||||
Bytes or sequences of bytes in the original byte stream that
|
||||
could not be converted to Unicode characters must be converted
|
||||
to U+FFFD REPLACEMENT CHARACTER code points. */
|
||||
|
||||
// XXX currently assuming input data is UTF-8; once we
|
||||
// build encoding detection this will no longer be the case
|
||||
//
|
||||
// We previously had an mbstring implementation here, but that
|
||||
// implementation is heavily non-conforming, so it's been
|
||||
// omitted.
|
||||
if (extension_loaded('iconv')) {
|
||||
// non-conforming
|
||||
$data = @iconv('UTF-8', 'UTF-8//IGNORE', $data);
|
||||
} else {
|
||||
// we can make a conforming native implementation
|
||||
throw new Exception('Not implemented, please install mbstring or iconv');
|
||||
}
|
||||
|
||||
/* One leading U+FEFF BYTE ORDER MARK character must be
|
||||
ignored if any are present. */
|
||||
if (substr($data, 0, 3) === "\xEF\xBB\xBF") {
|
||||
$data = substr($data, 3);
|
||||
}
|
||||
|
||||
/* All U+0000 NULL characters in the input must be replaced
|
||||
by U+FFFD REPLACEMENT CHARACTERs. Any occurrences of such
|
||||
characters is a parse error. */
|
||||
for ($i = 0, $count = substr_count($data, "\0"); $i < $count; $i++) {
|
||||
$this->errors[] = array(
|
||||
'type' => HTML5_Tokenizer::PARSEERROR,
|
||||
'data' => 'null-character'
|
||||
);
|
||||
}
|
||||
/* U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED
|
||||
(LF) characters are treated specially. Any CR characters
|
||||
that are followed by LF characters must be removed, and any
|
||||
CR characters not followed by LF characters must be converted
|
||||
to LF characters. Thus, newlines in HTML DOMs are represented
|
||||
by LF characters, and there are never any CR characters in the
|
||||
input to the tokenization stage. */
|
||||
$data = str_replace(
|
||||
array(
|
||||
"\0",
|
||||
"\r\n",
|
||||
"\r"
|
||||
),
|
||||
array(
|
||||
"\xEF\xBF\xBD",
|
||||
"\n",
|
||||
"\n"
|
||||
),
|
||||
$data
|
||||
);
|
||||
|
||||
/* Any occurrences of any characters in the ranges U+0001 to
|
||||
U+0008, U+000B, U+000E to U+001F, U+007F to U+009F,
|
||||
U+D800 to U+DFFF , U+FDD0 to U+FDEF, and
|
||||
characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF,
|
||||
U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE,
|
||||
U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF,
|
||||
U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE,
|
||||
U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and
|
||||
U+10FFFF are parse errors. (These are all control characters
|
||||
or permanently undefined Unicode characters.) */
|
||||
// Check PCRE is loaded.
|
||||
if (extension_loaded('pcre')) {
|
||||
$count = preg_match_all(
|
||||
'/(?:
|
||||
[\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B, U+000E to U+001F and U+007F
|
||||
|
|
||||
\xC2[\x80-\x9F] # U+0080 to U+009F
|
||||
|
|
||||
\xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF
|
||||
|
|
||||
\xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF
|
||||
|
|
||||
\xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF
|
||||
|
|
||||
[\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16})
|
||||
)/x',
|
||||
$data,
|
||||
$matches
|
||||
);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$this->errors[] = array(
|
||||
'type' => HTML5_Tokenizer::PARSEERROR,
|
||||
'data' => 'invalid-codepoint'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// XXX: Need non-PCRE impl, probably using substr_count
|
||||
}
|
||||
|
||||
$this->data = $data;
|
||||
$this->char = 0;
|
||||
$this->EOF = strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current line that the tokenizer is at.
|
||||
*/
|
||||
public function getCurrentLine() {
|
||||
// Check the string isn't empty
|
||||
if($this->EOF) {
|
||||
// Add one to $this->char because we want the number for the next
|
||||
// byte to be processed.
|
||||
return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1;
|
||||
} else {
|
||||
// If the string is empty, we are on the first line (sorta).
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current column of the current line that the tokenizer is at.
|
||||
*/
|
||||
public function getColumnOffset() {
|
||||
// strrpos is weird, and the offset needs to be negative for what we
|
||||
// want (i.e., the last \n before $this->char). This needs to not have
|
||||
// one (to make it point to the next character, the one we want the
|
||||
// position of) added to it because strrpos's behaviour includes the
|
||||
// final offset byte.
|
||||
$lastLine = strrpos($this->data, "\n", $this->char - 1 - strlen($this->data));
|
||||
|
||||
// However, for here we want the length up until the next byte to be
|
||||
// processed, so add one to the current byte ($this->char).
|
||||
if($lastLine !== false) {
|
||||
$findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine);
|
||||
} else {
|
||||
$findLengthOf = substr($this->data, 0, $this->char);
|
||||
}
|
||||
|
||||
// Get the length for the string we need.
|
||||
if(extension_loaded('iconv')) {
|
||||
return iconv_strlen($findLengthOf, 'utf-8');
|
||||
} elseif(extension_loaded('mbstring')) {
|
||||
return mb_strlen($findLengthOf, 'utf-8');
|
||||
} elseif(extension_loaded('xml')) {
|
||||
return strlen(utf8_decode($findLengthOf));
|
||||
} else {
|
||||
$count = count_chars($findLengthOf);
|
||||
// 0x80 = 0x7F - 0 + 1 (one added to get inclusive range)
|
||||
// 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range)
|
||||
return array_sum(array_slice($count, 0, 0x80)) +
|
||||
array_sum(array_slice($count, 0xC2, 0x33));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the currently consume character.
|
||||
* @note This performs bounds checking
|
||||
*/
|
||||
public function char() {
|
||||
return ($this->char++ < $this->EOF)
|
||||
? $this->data[$this->char - 1]
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all characters until EOF.
|
||||
* @note This performs bounds checking
|
||||
*/
|
||||
public function remainingChars() {
|
||||
if($this->char < $this->EOF) {
|
||||
$data = substr($this->data, $this->char);
|
||||
$this->char = $this->EOF;
|
||||
return $data;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches as far as possible until we reach a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
* @param $bytes Bytes to match.
|
||||
*/
|
||||
public function charsUntil($bytes, $max = null) {
|
||||
if ($this->char < $this->EOF) {
|
||||
if ($max === 0 || $max) {
|
||||
$len = strcspn($this->data, $bytes, $this->char, $max);
|
||||
} else {
|
||||
$len = strcspn($this->data, $bytes, $this->char);
|
||||
}
|
||||
$string = (string) substr($this->data, $this->char, $len);
|
||||
$this->char += $len;
|
||||
return $string;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches as far as possible with a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
* @param $bytes Bytes to match.
|
||||
*/
|
||||
public function charsWhile($bytes, $max = null) {
|
||||
if ($this->char < $this->EOF) {
|
||||
if ($max === 0 || $max) {
|
||||
$len = strspn($this->data, $bytes, $this->char, $max);
|
||||
} else {
|
||||
$len = strspn($this->data, $bytes, $this->char);
|
||||
}
|
||||
$string = (string) substr($this->data, $this->char, $len);
|
||||
$this->char += $len;
|
||||
return $string;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconsume one character.
|
||||
*/
|
||||
public function unget() {
|
||||
if ($this->char <= $this->EOF) {
|
||||
$this->char--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
|
||||
require_once dirname(__FILE__) . '/Data.php';
|
||||
require_once dirname(__FILE__) . '/InputStream.php';
|
||||
require_once dirname(__FILE__) . '/TreeBuilder.php';
|
||||
require_once dirname(__FILE__) . '/Tokenizer.php';
|
||||
|
||||
/**
|
||||
* Outwards facing interface for HTML5.
|
||||
*/
|
||||
class HTML5_Parser
|
||||
{
|
||||
/**
|
||||
* Parses a full HTML document.
|
||||
* @param $text HTML text to parse
|
||||
* @param $builder Custom builder implementation
|
||||
* @return Parsed HTML as DOMDocument
|
||||
*/
|
||||
static public function parse($text, $builder = null) {
|
||||
|
||||
// Cleanup invalid HTML
|
||||
$doc = new DOMDocument();
|
||||
|
||||
if (mb_detect_encoding($text, "UTF-8", true) == "UTF-8")
|
||||
@$doc->loadHTML('<?xml encoding="UTF-8" ?>'.$text);
|
||||
else
|
||||
@$doc->loadHTML($text);
|
||||
|
||||
$text = $doc->saveHTML();
|
||||
|
||||
$tokenizer = new HTML5_Tokenizer($text, $builder);
|
||||
$tokenizer->parse();
|
||||
return $tokenizer->save();
|
||||
}
|
||||
/**
|
||||
* Parses an HTML fragment.
|
||||
* @param $text HTML text to parse
|
||||
* @param $context String name of context element to pretend parsing is in.
|
||||
* @param $builder Custom builder implementation
|
||||
* @return Parsed HTML as DOMDocument
|
||||
*/
|
||||
static public function parseFragment($text, $context = null, $builder = null) {
|
||||
$tokenizer = new HTML5_Tokenizer($text, $builder);
|
||||
$tokenizer->parseFragment($context);
|
||||
return $tokenizer->save();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,83 +0,0 @@
|
|||
<?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';
|
|
@ -1,184 +0,0 @@
|
|||
<?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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
<?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);
|
|
@ -1,102 +0,0 @@
|
|||
<?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));
|
|
@ -1,195 +0,0 @@
|
|||
<?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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,207 +0,0 @@
|
|||
<?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];
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
<?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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
<?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];
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
<?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();
|
||||
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
<?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, array $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(\PDOStatement $objPDO, array $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(\PDOStatement $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 *scalar* information
|
||||
* of the query definition. if there are non-scalar information
|
||||
* added, the will be excluded from output
|
||||
*
|
||||
**/
|
||||
private function flattenQueryDefiniton(array $arrQueryDefinition) {
|
||||
|
||||
$strMessage = "\nQuery-Definiton:\n";
|
||||
|
||||
foreach($arrQueryDefinition AS $strKeyword => $strContent)
|
||||
if(is_scalar($strContent))
|
||||
$strMessage .= "$strKeyword: $strContent\n";
|
||||
|
||||
return $strMessage . "\n";
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<?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));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,955 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (!function_exists('curl_init')) {
|
||||
throw new Exception('Facebook needs the CURL PHP extension.');
|
||||
}
|
||||
if (!function_exists('json_decode')) {
|
||||
throw new Exception('Facebook needs the JSON PHP extension.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when an API call returns an exception.
|
||||
*
|
||||
* @author Naitik Shah <naitik@facebook.com>
|
||||
*/
|
||||
class FacebookApiException extends Exception
|
||||
{
|
||||
/**
|
||||
* The result from the API server that represents the exception information.
|
||||
*/
|
||||
protected $result;
|
||||
|
||||
/**
|
||||
* Make a new API Exception with the given result.
|
||||
*
|
||||
* @param Array $result the result from the API server
|
||||
*/
|
||||
public function __construct($result) {
|
||||
$this->result = $result;
|
||||
|
||||
$code = isset($result['error_code']) ? $result['error_code'] : 0;
|
||||
|
||||
if (isset($result['error_description'])) {
|
||||
// OAuth 2.0 Draft 10 style
|
||||
$msg = $result['error_description'];
|
||||
} else if (isset($result['error']) && is_array($result['error'])) {
|
||||
// OAuth 2.0 Draft 00 style
|
||||
$msg = $result['error']['message'];
|
||||
} else if (isset($result['error_msg'])) {
|
||||
// Rest server style
|
||||
$msg = $result['error_msg'];
|
||||
} else {
|
||||
$msg = 'Unknown Error. Check getResult()';
|
||||
}
|
||||
|
||||
parent::__construct($msg, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated result object returned by the API server.
|
||||
*
|
||||
* @returns Array the result from the API server
|
||||
*/
|
||||
public function getResult() {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated type for the error. This will default to
|
||||
* 'Exception' when a type is not available.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function getType() {
|
||||
if (isset($this->result['error'])) {
|
||||
$error = $this->result['error'];
|
||||
if (is_string($error)) {
|
||||
// OAuth 2.0 Draft 10 style
|
||||
return $error;
|
||||
} else if (is_array($error)) {
|
||||
// OAuth 2.0 Draft 00 style
|
||||
if (isset($error['type'])) {
|
||||
return $error['type'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'Exception';
|
||||
}
|
||||
|
||||
/**
|
||||
* To make debugging easier.
|
||||
*
|
||||
* @returns String the string representation of the error
|
||||
*/
|
||||
public function __toString() {
|
||||
$str = $this->getType() . ': ';
|
||||
if ($this->code != 0) {
|
||||
$str .= $this->code . ': ';
|
||||
}
|
||||
return $str . $this->message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the Facebook Platform.
|
||||
*
|
||||
* @author Naitik Shah <naitik@facebook.com>
|
||||
*/
|
||||
class Facebook
|
||||
{
|
||||
/**
|
||||
* Version.
|
||||
*/
|
||||
const VERSION = '2.1.2';
|
||||
|
||||
/**
|
||||
* Default options for curl.
|
||||
*/
|
||||
public static $CURL_OPTS = array(
|
||||
CURLOPT_CONNECTTIMEOUT => 10,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 60,
|
||||
CURLOPT_USERAGENT => 'facebook-php-2.0',
|
||||
);
|
||||
|
||||
/**
|
||||
* List of query parameters that get automatically dropped when rebuilding
|
||||
* the current URL.
|
||||
*/
|
||||
protected static $DROP_QUERY_PARAMS = array(
|
||||
'session',
|
||||
'signed_request',
|
||||
);
|
||||
|
||||
/**
|
||||
* Maps aliases to Facebook domains.
|
||||
*/
|
||||
public static $DOMAIN_MAP = array(
|
||||
'api' => 'https://api.facebook.com/',
|
||||
'api_read' => 'https://api-read.facebook.com/',
|
||||
'graph' => 'https://graph.facebook.com/',
|
||||
'www' => 'https://www.facebook.com/',
|
||||
);
|
||||
|
||||
/**
|
||||
* The Application ID.
|
||||
*/
|
||||
protected $appId;
|
||||
|
||||
/**
|
||||
* The Application API Secret.
|
||||
*/
|
||||
protected $apiSecret;
|
||||
|
||||
/**
|
||||
* The active user session, if one is available.
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* The data from the signed_request token.
|
||||
*/
|
||||
protected $signedRequest;
|
||||
|
||||
/**
|
||||
* Indicates that we already loaded the session as best as we could.
|
||||
*/
|
||||
protected $sessionLoaded = false;
|
||||
|
||||
/**
|
||||
* Indicates if Cookie support should be enabled.
|
||||
*/
|
||||
protected $cookieSupport = false;
|
||||
|
||||
/**
|
||||
* Base domain for the Cookie.
|
||||
*/
|
||||
protected $baseDomain = '';
|
||||
|
||||
/**
|
||||
* Indicates if the CURL based @ syntax for file uploads is enabled.
|
||||
*/
|
||||
protected $fileUploadSupport = false;
|
||||
|
||||
/**
|
||||
* Initialize a Facebook Application.
|
||||
*
|
||||
* The configuration:
|
||||
* - appId: the application ID
|
||||
* - secret: the application secret
|
||||
* - cookie: (optional) boolean true to enable cookie support
|
||||
* - domain: (optional) domain for the cookie
|
||||
* - fileUpload: (optional) boolean indicating if file uploads are enabled
|
||||
*
|
||||
* @param Array $config the application configuration
|
||||
*/
|
||||
public function __construct($config) {
|
||||
$this->setAppId($config['appId']);
|
||||
$this->setApiSecret($config['secret']);
|
||||
if (isset($config['cookie'])) {
|
||||
$this->setCookieSupport($config['cookie']);
|
||||
}
|
||||
if (isset($config['domain'])) {
|
||||
$this->setBaseDomain($config['domain']);
|
||||
}
|
||||
if (isset($config['fileUpload'])) {
|
||||
$this->setFileUploadSupport($config['fileUpload']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Application ID.
|
||||
*
|
||||
* @param String $appId the Application ID
|
||||
*/
|
||||
public function setAppId($appId) {
|
||||
$this->appId = $appId;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Application ID.
|
||||
*
|
||||
* @return String the Application ID
|
||||
*/
|
||||
public function getAppId() {
|
||||
return $this->appId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the API Secret.
|
||||
*
|
||||
* @param String $appId the API Secret
|
||||
*/
|
||||
public function setApiSecret($apiSecret) {
|
||||
$this->apiSecret = $apiSecret;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API Secret.
|
||||
*
|
||||
* @return String the API Secret
|
||||
*/
|
||||
public function getApiSecret() {
|
||||
return $this->apiSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Cookie Support status.
|
||||
*
|
||||
* @param Boolean $cookieSupport the Cookie Support status
|
||||
*/
|
||||
public function setCookieSupport($cookieSupport) {
|
||||
$this->cookieSupport = $cookieSupport;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cookie Support status.
|
||||
*
|
||||
* @return Boolean the Cookie Support status
|
||||
*/
|
||||
public function useCookieSupport() {
|
||||
return $this->cookieSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base domain for the Cookie.
|
||||
*
|
||||
* @param String $domain the base domain
|
||||
*/
|
||||
public function setBaseDomain($domain) {
|
||||
$this->baseDomain = $domain;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base domain for the Cookie.
|
||||
*
|
||||
* @return String the base domain
|
||||
*/
|
||||
public function getBaseDomain() {
|
||||
return $this->baseDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file upload support status.
|
||||
*
|
||||
* @param String $domain the base domain
|
||||
*/
|
||||
public function setFileUploadSupport($fileUploadSupport) {
|
||||
$this->fileUploadSupport = $fileUploadSupport;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file upload support status.
|
||||
*
|
||||
* @return String the base domain
|
||||
*/
|
||||
public function useFileUploadSupport() {
|
||||
return $this->fileUploadSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data from a signed_request token
|
||||
*
|
||||
* @return String the base domain
|
||||
*/
|
||||
public function getSignedRequest() {
|
||||
if (!$this->signedRequest) {
|
||||
if (isset($_REQUEST['signed_request'])) {
|
||||
$this->signedRequest = $this->parseSignedRequest(
|
||||
$_REQUEST['signed_request']);
|
||||
}
|
||||
}
|
||||
return $this->signedRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Session.
|
||||
*
|
||||
* @param Array $session the session
|
||||
* @param Boolean $write_cookie indicate if a cookie should be written. this
|
||||
* value is ignored if cookie support has been disabled.
|
||||
*/
|
||||
public function setSession($session=null, $write_cookie=true) {
|
||||
$session = $this->validateSessionObject($session);
|
||||
$this->sessionLoaded = true;
|
||||
$this->session = $session;
|
||||
if ($write_cookie) {
|
||||
$this->setCookieFromSession($session);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the session object. This will automatically look for a signed session
|
||||
* sent via the signed_request, Cookie or Query Parameters if needed.
|
||||
*
|
||||
* @return Array the session
|
||||
*/
|
||||
public function getSession() {
|
||||
if (!$this->sessionLoaded) {
|
||||
$session = null;
|
||||
$write_cookie = true;
|
||||
|
||||
// try loading session from signed_request in $_REQUEST
|
||||
$signedRequest = $this->getSignedRequest();
|
||||
if ($signedRequest) {
|
||||
// sig is good, use the signedRequest
|
||||
$session = $this->createSessionFromSignedRequest($signedRequest);
|
||||
}
|
||||
|
||||
// try loading session from $_REQUEST
|
||||
if (!$session && isset($_REQUEST['session'])) {
|
||||
$session = json_decode(
|
||||
get_magic_quotes_gpc()
|
||||
? stripslashes($_REQUEST['session'])
|
||||
: $_REQUEST['session'],
|
||||
true
|
||||
);
|
||||
$session = $this->validateSessionObject($session);
|
||||
}
|
||||
|
||||
// try loading session from cookie if necessary
|
||||
if (!$session && $this->useCookieSupport()) {
|
||||
$cookieName = $this->getSessionCookieName();
|
||||
if (isset($_COOKIE[$cookieName])) {
|
||||
$session = array();
|
||||
parse_str(trim(
|
||||
get_magic_quotes_gpc()
|
||||
? stripslashes($_COOKIE[$cookieName])
|
||||
: $_COOKIE[$cookieName],
|
||||
'"'
|
||||
), $session);
|
||||
$session = $this->validateSessionObject($session);
|
||||
// write only if we need to delete a invalid session cookie
|
||||
$write_cookie = empty($session);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setSession($session, $write_cookie);
|
||||
}
|
||||
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UID from the session.
|
||||
*
|
||||
* @return String the UID if available
|
||||
*/
|
||||
public function getUser() {
|
||||
$session = $this->getSession();
|
||||
return $session ? $session['uid'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a OAuth access token.
|
||||
*
|
||||
* @return String the access token
|
||||
*/
|
||||
public function getAccessToken() {
|
||||
$session = $this->getSession();
|
||||
// either user session signed, or app signed
|
||||
if ($session) {
|
||||
return $session['access_token'];
|
||||
} else {
|
||||
return $this->getAppId() .'|'. $this->getApiSecret();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Login URL for use with redirects. By default, full page redirect is
|
||||
* assumed. If you are using the generated URL with a window.open() call in
|
||||
* JavaScript, you can pass in display=popup as part of the $params.
|
||||
*
|
||||
* The parameters:
|
||||
* - next: the url to go to after a successful login
|
||||
* - cancel_url: the url to go to after the user cancels
|
||||
* - req_perms: comma separated list of requested extended perms
|
||||
* - display: can be "page" (default, full page) or "popup"
|
||||
*
|
||||
* @param Array $params provide custom parameters
|
||||
* @return String the URL for the login flow
|
||||
*/
|
||||
public function getLoginUrl($params=array()) {
|
||||
$currentUrl = $this->getCurrentUrl();
|
||||
return $this->getUrl(
|
||||
'www',
|
||||
'login.php',
|
||||
array_merge(array(
|
||||
'api_key' => $this->getAppId(),
|
||||
'cancel_url' => $currentUrl,
|
||||
'display' => 'page',
|
||||
'fbconnect' => 1,
|
||||
'next' => $currentUrl,
|
||||
'return_session' => 1,
|
||||
'session_version' => 3,
|
||||
'v' => '1.0',
|
||||
), $params)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Logout URL suitable for use with redirects.
|
||||
*
|
||||
* The parameters:
|
||||
* - next: the url to go to after a successful logout
|
||||
*
|
||||
* @param Array $params provide custom parameters
|
||||
* @return String the URL for the logout flow
|
||||
*/
|
||||
public function getLogoutUrl($params=array()) {
|
||||
return $this->getUrl(
|
||||
'www',
|
||||
'logout.php',
|
||||
array_merge(array(
|
||||
'next' => $this->getCurrentUrl(),
|
||||
'access_token' => $this->getAccessToken(),
|
||||
), $params)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a login status URL to fetch the status from facebook.
|
||||
*
|
||||
* The parameters:
|
||||
* - ok_session: the URL to go to if a session is found
|
||||
* - no_session: the URL to go to if the user is not connected
|
||||
* - no_user: the URL to go to if the user is not signed into facebook
|
||||
*
|
||||
* @param Array $params provide custom parameters
|
||||
* @return String the URL for the logout flow
|
||||
*/
|
||||
public function getLoginStatusUrl($params=array()) {
|
||||
return $this->getUrl(
|
||||
'www',
|
||||
'extern/login_status.php',
|
||||
array_merge(array(
|
||||
'api_key' => $this->getAppId(),
|
||||
'no_session' => $this->getCurrentUrl(),
|
||||
'no_user' => $this->getCurrentUrl(),
|
||||
'ok_session' => $this->getCurrentUrl(),
|
||||
'session_version' => 3,
|
||||
), $params)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an API call.
|
||||
*
|
||||
* @param Array $params the API call parameters
|
||||
* @return the decoded response
|
||||
*/
|
||||
public function api(/* polymorphic */) {
|
||||
$args = func_get_args();
|
||||
if (is_array($args[0])) {
|
||||
return $this->_restserver($args[0]);
|
||||
} else {
|
||||
return call_user_func_array(array($this, '_graph'), $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the old restserver.php endpoint.
|
||||
*
|
||||
* @param Array $params method call object
|
||||
* @return the decoded response object
|
||||
* @throws FacebookApiException
|
||||
*/
|
||||
protected function _restserver($params) {
|
||||
// generic application level parameters
|
||||
$params['api_key'] = $this->getAppId();
|
||||
$params['format'] = 'json-strings';
|
||||
|
||||
$result = json_decode($this->_oauthRequest(
|
||||
$this->getApiUrl($params['method']),
|
||||
$params
|
||||
), true);
|
||||
|
||||
// results are returned, errors are thrown
|
||||
if (is_array($result) && isset($result['error_code'])) {
|
||||
throw new FacebookApiException($result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the Graph API.
|
||||
*
|
||||
* @param String $path the path (required)
|
||||
* @param String $method the http method (default 'GET')
|
||||
* @param Array $params the query/post data
|
||||
* @return the decoded response object
|
||||
* @throws FacebookApiException
|
||||
*/
|
||||
protected function _graph($path, $method='GET', $params=array()) {
|
||||
if (is_array($method) && empty($params)) {
|
||||
$params = $method;
|
||||
$method = 'GET';
|
||||
}
|
||||
$params['method'] = $method; // method override as we always do a POST
|
||||
|
||||
$result = json_decode($this->_oauthRequest(
|
||||
$this->getUrl('graph', $path),
|
||||
$params
|
||||
), true);
|
||||
|
||||
// results are returned, errors are thrown
|
||||
if (is_array($result) && isset($result['error'])) {
|
||||
$e = new FacebookApiException($result);
|
||||
switch ($e->getType()) {
|
||||
// OAuth 2.0 Draft 00 style
|
||||
case 'OAuthException':
|
||||
// OAuth 2.0 Draft 10 style
|
||||
case 'invalid_token':
|
||||
$this->setSession(null);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a OAuth Request
|
||||
*
|
||||
* @param String $path the path (required)
|
||||
* @param Array $params the query/post data
|
||||
* @return the decoded response object
|
||||
* @throws FacebookApiException
|
||||
*/
|
||||
protected function _oauthRequest($url, $params) {
|
||||
if (!isset($params['access_token'])) {
|
||||
$params['access_token'] = $this->getAccessToken();
|
||||
}
|
||||
|
||||
// json_encode all params values that are not strings
|
||||
foreach ($params as $key => $value) {
|
||||
if (!is_string($value)) {
|
||||
$params[$key] = json_encode($value);
|
||||
}
|
||||
}
|
||||
return $this->makeRequest($url, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an HTTP request. This method can be overriden by subclasses if
|
||||
* developers want to do fancier things or use something other than curl to
|
||||
* make the request.
|
||||
*
|
||||
* @param String $url the URL to make the request to
|
||||
* @param Array $params the parameters to use for the POST body
|
||||
* @param CurlHandler $ch optional initialized curl handle
|
||||
* @return String the response text
|
||||
*/
|
||||
protected function makeRequest($url, $params, $ch=null) {
|
||||
if (!$ch) {
|
||||
$ch = curl_init();
|
||||
}
|
||||
|
||||
$opts = self::$CURL_OPTS;
|
||||
if ($this->useFileUploadSupport()) {
|
||||
$opts[CURLOPT_POSTFIELDS] = $params;
|
||||
} else {
|
||||
$opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
|
||||
}
|
||||
$opts[CURLOPT_URL] = $url;
|
||||
|
||||
// disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
|
||||
// for 2 seconds if the server does not support this header.
|
||||
if (isset($opts[CURLOPT_HTTPHEADER])) {
|
||||
$existing_headers = $opts[CURLOPT_HTTPHEADER];
|
||||
$existing_headers[] = 'Expect:';
|
||||
$opts[CURLOPT_HTTPHEADER] = $existing_headers;
|
||||
} else {
|
||||
$opts[CURLOPT_HTTPHEADER] = array('Expect:');
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, $opts);
|
||||
$result = curl_exec($ch);
|
||||
if ($result === false) {
|
||||
$e = new FacebookApiException(array(
|
||||
'error_code' => curl_errno($ch),
|
||||
'error' => array(
|
||||
'message' => curl_error($ch),
|
||||
'type' => 'CurlException',
|
||||
),
|
||||
));
|
||||
curl_close($ch);
|
||||
throw $e;
|
||||
}
|
||||
curl_close($ch);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the Cookie that contains the session.
|
||||
*
|
||||
* @return String the cookie name
|
||||
*/
|
||||
protected function getSessionCookieName() {
|
||||
return 'fbs_' . $this->getAppId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a JS Cookie based on the _passed in_ session. It does not use the
|
||||
* currently stored session -- you need to explicitly pass it in.
|
||||
*
|
||||
* @param Array $session the session to use for setting the cookie
|
||||
*/
|
||||
protected function setCookieFromSession($session=null) {
|
||||
if (!$this->useCookieSupport()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cookieName = $this->getSessionCookieName();
|
||||
$value = 'deleted';
|
||||
$expires = time() - 3600;
|
||||
$domain = $this->getBaseDomain();
|
||||
if ($session) {
|
||||
$value = '"' . http_build_query($session, null, '&') . '"';
|
||||
if (isset($session['base_domain'])) {
|
||||
$domain = $session['base_domain'];
|
||||
}
|
||||
$expires = $session['expires'];
|
||||
}
|
||||
|
||||
// prepend dot if a domain is found
|
||||
if ($domain) {
|
||||
$domain = '.' . $domain;
|
||||
}
|
||||
|
||||
// if an existing cookie is not set, we dont need to delete it
|
||||
if ($value == 'deleted' && empty($_COOKIE[$cookieName])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (headers_sent()) {
|
||||
self::errorLog('Could not set cookie. Headers already sent.');
|
||||
|
||||
// ignore for code coverage as we will never be able to setcookie in a CLI
|
||||
// environment
|
||||
// @codeCoverageIgnoreStart
|
||||
} else {
|
||||
setcookie($cookieName, $value, $expires, '/', $domain);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a session_version=3 style session object.
|
||||
*
|
||||
* @param Array $session the session object
|
||||
* @return Array the session object if it validates, null otherwise
|
||||
*/
|
||||
protected function validateSessionObject($session) {
|
||||
// make sure some essential fields exist
|
||||
if (is_array($session) &&
|
||||
isset($session['uid']) &&
|
||||
isset($session['access_token']) &&
|
||||
isset($session['sig'])) {
|
||||
// validate the signature
|
||||
$session_without_sig = $session;
|
||||
unset($session_without_sig['sig']);
|
||||
$expected_sig = self::generateSignature(
|
||||
$session_without_sig,
|
||||
$this->getApiSecret()
|
||||
);
|
||||
if ($session['sig'] != $expected_sig) {
|
||||
self::errorLog('Got invalid session signature in cookie.');
|
||||
$session = null;
|
||||
}
|
||||
// check expiry time
|
||||
} else {
|
||||
$session = null;
|
||||
}
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns something that looks like our JS session object from the
|
||||
* signed token's data
|
||||
*
|
||||
* TODO: Nuke this once the login flow uses OAuth2
|
||||
*
|
||||
* @param Array the output of getSignedRequest
|
||||
* @return Array Something that will work as a session
|
||||
*/
|
||||
protected function createSessionFromSignedRequest($data) {
|
||||
if (!isset($data['oauth_token'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$session = array(
|
||||
'uid' => $data['user_id'],
|
||||
'access_token' => $data['oauth_token'],
|
||||
'expires' => $data['expires'],
|
||||
);
|
||||
|
||||
// put a real sig, so that validateSignature works
|
||||
$session['sig'] = self::generateSignature(
|
||||
$session,
|
||||
$this->getApiSecret()
|
||||
);
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a signed_request and validates the signature.
|
||||
* Then saves it in $this->signed_data
|
||||
*
|
||||
* @param String A signed token
|
||||
* @param Boolean Should we remove the parts of the payload that
|
||||
* are used by the algorithm?
|
||||
* @return Array the payload inside it or null if the sig is wrong
|
||||
*/
|
||||
protected function parseSignedRequest($signed_request) {
|
||||
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
|
||||
|
||||
// decode the data
|
||||
$sig = self::base64UrlDecode($encoded_sig);
|
||||
$data = json_decode(self::base64UrlDecode($payload), true);
|
||||
|
||||
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
|
||||
self::errorLog('Unknown algorithm. Expected HMAC-SHA256');
|
||||
return null;
|
||||
}
|
||||
|
||||
// check sig
|
||||
$expected_sig = hash_hmac('sha256', $payload,
|
||||
$this->getApiSecret(), $raw = true);
|
||||
if ($sig !== $expected_sig) {
|
||||
self::errorLog('Bad Signed JSON signature!');
|
||||
return null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the URL for api given parameters.
|
||||
*
|
||||
* @param $method String the method name.
|
||||
* @return String the URL for the given parameters
|
||||
*/
|
||||
protected function getApiUrl($method) {
|
||||
static $READ_ONLY_CALLS =
|
||||
array('admin.getallocation' => 1,
|
||||
'admin.getappproperties' => 1,
|
||||
'admin.getbannedusers' => 1,
|
||||
'admin.getlivestreamvialink' => 1,
|
||||
'admin.getmetrics' => 1,
|
||||
'admin.getrestrictioninfo' => 1,
|
||||
'application.getpublicinfo' => 1,
|
||||
'auth.getapppublickey' => 1,
|
||||
'auth.getsession' => 1,
|
||||
'auth.getsignedpublicsessiondata' => 1,
|
||||
'comments.get' => 1,
|
||||
'connect.getunconnectedfriendscount' => 1,
|
||||
'dashboard.getactivity' => 1,
|
||||
'dashboard.getcount' => 1,
|
||||
'dashboard.getglobalnews' => 1,
|
||||
'dashboard.getnews' => 1,
|
||||
'dashboard.multigetcount' => 1,
|
||||
'dashboard.multigetnews' => 1,
|
||||
'data.getcookies' => 1,
|
||||
'events.get' => 1,
|
||||
'events.getmembers' => 1,
|
||||
'fbml.getcustomtags' => 1,
|
||||
'feed.getappfriendstories' => 1,
|
||||
'feed.getregisteredtemplatebundlebyid' => 1,
|
||||
'feed.getregisteredtemplatebundles' => 1,
|
||||
'fql.multiquery' => 1,
|
||||
'fql.query' => 1,
|
||||
'friends.arefriends' => 1,
|
||||
'friends.get' => 1,
|
||||
'friends.getappusers' => 1,
|
||||
'friends.getlists' => 1,
|
||||
'friends.getmutualfriends' => 1,
|
||||
'gifts.get' => 1,
|
||||
'groups.get' => 1,
|
||||
'groups.getmembers' => 1,
|
||||
'intl.gettranslations' => 1,
|
||||
'links.get' => 1,
|
||||
'notes.get' => 1,
|
||||
'notifications.get' => 1,
|
||||
'pages.getinfo' => 1,
|
||||
'pages.isadmin' => 1,
|
||||
'pages.isappadded' => 1,
|
||||
'pages.isfan' => 1,
|
||||
'permissions.checkavailableapiaccess' => 1,
|
||||
'permissions.checkgrantedapiaccess' => 1,
|
||||
'photos.get' => 1,
|
||||
'photos.getalbums' => 1,
|
||||
'photos.gettags' => 1,
|
||||
'profile.getinfo' => 1,
|
||||
'profile.getinfooptions' => 1,
|
||||
'stream.get' => 1,
|
||||
'stream.getcomments' => 1,
|
||||
'stream.getfilters' => 1,
|
||||
'users.getinfo' => 1,
|
||||
'users.getloggedinuser' => 1,
|
||||
'users.getstandardinfo' => 1,
|
||||
'users.hasapppermission' => 1,
|
||||
'users.isappuser' => 1,
|
||||
'users.isverified' => 1,
|
||||
'video.getuploadlimits' => 1);
|
||||
$name = 'api';
|
||||
if (isset($READ_ONLY_CALLS[strtolower($method)])) {
|
||||
$name = 'api_read';
|
||||
}
|
||||
return self::getUrl($name, 'restserver.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the URL for given domain alias, path and parameters.
|
||||
*
|
||||
* @param $name String the name of the domain
|
||||
* @param $path String optional path (without a leading slash)
|
||||
* @param $params Array optional query parameters
|
||||
* @return String the URL for the given parameters
|
||||
*/
|
||||
protected function getUrl($name, $path='', $params=array()) {
|
||||
$url = self::$DOMAIN_MAP[$name];
|
||||
if ($path) {
|
||||
if ($path[0] === '/') {
|
||||
$path = substr($path, 1);
|
||||
}
|
||||
$url .= $path;
|
||||
}
|
||||
if ($params) {
|
||||
$url .= '?' . http_build_query($params, null, '&');
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Current URL, stripping it of known FB parameters that should
|
||||
* not persist.
|
||||
*
|
||||
* @return String the current URL
|
||||
*/
|
||||
protected function getCurrentUrl() {
|
||||
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'
|
||||
? 'https://'
|
||||
: 'http://';
|
||||
$currentUrl = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$parts = parse_url($currentUrl);
|
||||
|
||||
// drop known fb params
|
||||
$query = '';
|
||||
if (!empty($parts['query'])) {
|
||||
$params = array();
|
||||
parse_str($parts['query'], $params);
|
||||
foreach(self::$DROP_QUERY_PARAMS as $key) {
|
||||
unset($params[$key]);
|
||||
}
|
||||
if (!empty($params)) {
|
||||
$query = '?' . http_build_query($params, null, '&');
|
||||
}
|
||||
}
|
||||
|
||||
// use port if non default
|
||||
$port =
|
||||
isset($parts['port']) &&
|
||||
(($protocol === 'http://' && $parts['port'] !== 80) ||
|
||||
($protocol === 'https://' && $parts['port'] !== 443))
|
||||
? ':' . $parts['port'] : '';
|
||||
|
||||
// rebuild
|
||||
return $protocol . $parts['host'] . $port . $parts['path'] . $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a signature for the given params and secret.
|
||||
*
|
||||
* @param Array $params the parameters to sign
|
||||
* @param String $secret the secret to sign with
|
||||
* @return String the generated signature
|
||||
*/
|
||||
protected static function generateSignature($params, $secret) {
|
||||
// work with sorted data
|
||||
ksort($params);
|
||||
|
||||
// generate the base string
|
||||
$base_string = '';
|
||||
foreach($params as $key => $value) {
|
||||
$base_string .= $key . '=' . $value;
|
||||
}
|
||||
$base_string .= $secret;
|
||||
|
||||
return md5($base_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints to the error log if you aren't in command line mode.
|
||||
*
|
||||
* @param String log message
|
||||
*/
|
||||
protected static function errorLog($msg) {
|
||||
// disable error log if we are running in a CLI environment
|
||||
// @codeCoverageIgnoreStart
|
||||
if (php_sapi_name() != 'cli') {
|
||||
error_log($msg);
|
||||
}
|
||||
// uncomment this if you want to see the errors on the page
|
||||
// print 'error_log: '.$msg."\n";
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 encoding that doesn't need to be urlencode()ed.
|
||||
* Exactly the same as base64_encode except it uses
|
||||
* - instead of +
|
||||
* _ instead of /
|
||||
*
|
||||
* @param String base64UrlEncodeded string
|
||||
*/
|
||||
protected static function base64UrlDecode($input) {
|
||||
return base64_decode(strtr($input, '-_', '+/'));
|
||||
}
|
||||
}
|
974
mod/content.php
974
mod/content.php
|
@ -1,974 +0,0 @@
|
|||
<?php
|
||||
|
||||
// This is a purely experimental module and is not yet generally useful.
|
||||
|
||||
// The eventual goal is to provide a json backend to fetch content and fill the current page.
|
||||
// The page will be filled in on the frontend using javascript.
|
||||
// At the present time this page is based on "network", but the hope is to extend to serving
|
||||
// any content (wall, community, search, etc.).
|
||||
// All search parameters, etc. will be managed in javascript and sent as request params.
|
||||
// Security will be managed on the backend.
|
||||
// There is no "pagination query", but we will manage the "current page" on the client
|
||||
// and provide a link to fetch the next page - until there are no pages left to fetch.
|
||||
|
||||
// With the exception of complex tag and text searches, this prototype is incredibly
|
||||
// fast - e.g. one or two milliseconds to fetch parent items for the current content,
|
||||
// and 10-20 milliseconds to fetch all the child items.
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\System;
|
||||
|
||||
function content_content(App $a, $update = 0) {
|
||||
|
||||
require_once('include/conversation.php');
|
||||
|
||||
|
||||
// Currently security is based on the logged in user
|
||||
|
||||
if (! local_user()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$arr = array('query' => $a->query_string);
|
||||
|
||||
call_hooks('content_content_init', $arr);
|
||||
|
||||
|
||||
$datequery = $datequery2 = '';
|
||||
|
||||
$group = 0;
|
||||
|
||||
$nouveau = false;
|
||||
|
||||
if($a->argc > 1) {
|
||||
for($x = 1; $x < $a->argc; $x ++) {
|
||||
if(is_a_date_arg($a->argv[$x])) {
|
||||
if($datequery)
|
||||
$datequery2 = escape_tags($a->argv[$x]);
|
||||
else {
|
||||
$datequery = escape_tags($a->argv[$x]);
|
||||
$_GET['order'] = 'post';
|
||||
}
|
||||
}
|
||||
elseif($a->argv[$x] === 'new') {
|
||||
$nouveau = true;
|
||||
}
|
||||
elseif(intval($a->argv[$x])) {
|
||||
$group = intval($a->argv[$x]);
|
||||
$def_acl = array('allow_gid' => '<' . $group . '>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$o = '';
|
||||
|
||||
|
||||
|
||||
$contact_id = $a->cid;
|
||||
|
||||
require_once('include/acl_selectors.php');
|
||||
|
||||
$cid = ((x($_GET,'cid')) ? intval($_GET['cid']) : 0);
|
||||
$star = ((x($_GET,'star')) ? intval($_GET['star']) : 0);
|
||||
$bmark = ((x($_GET,'bmark')) ? intval($_GET['bmark']) : 0);
|
||||
$order = ((x($_GET,'order')) ? notags($_GET['order']) : 'comment');
|
||||
$liked = ((x($_GET,'liked')) ? intval($_GET['liked']) : 0);
|
||||
$conv = ((x($_GET,'conv')) ? intval($_GET['conv']) : 0);
|
||||
$spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0);
|
||||
$nets = ((x($_GET,'nets')) ? $_GET['nets'] : '');
|
||||
$cmin = ((x($_GET,'cmin')) ? intval($_GET['cmin']) : 0);
|
||||
$cmax = ((x($_GET,'cmax')) ? intval($_GET['cmax']) : 99);
|
||||
$file = ((x($_GET,'file')) ? $_GET['file'] : '');
|
||||
|
||||
|
||||
|
||||
if(x($_GET,'search') || x($_GET,'file'))
|
||||
$nouveau = true;
|
||||
if($cid)
|
||||
$def_acl = array('allow_cid' => '<' . intval($cid) . '>');
|
||||
|
||||
if($nets) {
|
||||
$r = q("select id from contact where uid = %d and network = '%s' and self = 0",
|
||||
intval(local_user()),
|
||||
dbesc($nets)
|
||||
);
|
||||
|
||||
$str = '';
|
||||
if (dbm::is_result($r))
|
||||
foreach($r as $rr)
|
||||
$str .= '<' . $rr['id'] . '>';
|
||||
if(strlen($str))
|
||||
$def_acl = array('allow_cid' => $str);
|
||||
}
|
||||
|
||||
|
||||
$sql_options = (($star) ? " and starred = 1 " : '');
|
||||
$sql_options .= (($bmark) ? " and bookmark = 1 " : '');
|
||||
|
||||
$sql_nets = (($nets) ? sprintf(" and `contact`.`network` = '%s' ", dbesc($nets)) : '');
|
||||
|
||||
$sql_extra = " AND `item`.`parent` IN ( SELECT `parent` FROM `item` WHERE `id` = `parent` $sql_options ) ";
|
||||
|
||||
if($group) {
|
||||
$r = q("SELECT `name`, `id` FROM `group` WHERE `id` = %d AND `uid` = %d LIMIT 1",
|
||||
intval($group),
|
||||
intval($_SESSION['uid'])
|
||||
);
|
||||
if (! dbm::is_result($r)) {
|
||||
if($update)
|
||||
killme();
|
||||
notice( t('No such group') . EOL );
|
||||
goaway(System::baseUrl(true) . '/network');
|
||||
// NOTREACHED
|
||||
}
|
||||
|
||||
$contacts = expand_groups(array($group));
|
||||
if((is_array($contacts)) && count($contacts)) {
|
||||
$contact_str = implode(',',$contacts);
|
||||
}
|
||||
else {
|
||||
$contact_str = ' 0 ';
|
||||
info( t('Group is empty'));
|
||||
}
|
||||
|
||||
$sql_extra = " AND `item`.`parent` IN ( SELECT DISTINCT(`parent`) FROM `item` WHERE 1 $sql_options AND ( `contact-id` IN ( $contact_str ) OR `allow_gid` like '" . protect_sprintf('%<' . intval($group) . '>%') . "' ) and deleted = 0 ) ";
|
||||
$o = replace_macros(get_markup_template("section_title.tpl"),array(
|
||||
'$title' => sprintf( t('Group: %s'), $r[0]['name'])
|
||||
)) . $o;
|
||||
}
|
||||
elseif($cid) {
|
||||
|
||||
$r = q("SELECT `id`,`name`,`network`,`writable`,`nurl` FROM `contact` WHERE `id` = %d
|
||||
AND `blocked` = 0 AND `pending` = 0 LIMIT 1",
|
||||
intval($cid)
|
||||
);
|
||||
if (dbm::is_result($r)) {
|
||||
$sql_extra = " AND `item`.`parent` IN ( SELECT DISTINCT(`parent`) FROM `item` WHERE 1 $sql_options AND `contact-id` = " . intval($cid) . " and deleted = 0 ) ";
|
||||
|
||||
}
|
||||
else {
|
||||
killme();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$sql_extra3 = '';
|
||||
|
||||
if($datequery) {
|
||||
$sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery))));
|
||||
}
|
||||
if($datequery2) {
|
||||
$sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2))));
|
||||
}
|
||||
|
||||
$sql_extra2 = (($nouveau) ? '' : " AND `item`.`parent` = `item`.`id` ");
|
||||
$sql_extra3 = (($nouveau) ? '' : $sql_extra3);
|
||||
$sql_table = "`item`";
|
||||
|
||||
if(x($_GET,'search')) {
|
||||
$search = escape_tags($_GET['search']);
|
||||
|
||||
if(strpos($search,'#') === 0) {
|
||||
$tag = true;
|
||||
$search = substr($search,1);
|
||||
}
|
||||
|
||||
if (get_config('system','only_tag_search'))
|
||||
$tag = true;
|
||||
|
||||
if($tag) {
|
||||
//$sql_extra = sprintf(" AND `term`.`term` = '%s' AND `term`.`otype` = %d AND `term`.`type` = %d ",
|
||||
// dbesc(protect_sprintf($search)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG));
|
||||
//$sql_table = "`term` INNER JOIN `item` ON `item`.`id` = `term`.`oid` AND `item`.`uid` = `term`.`uid` ";
|
||||
|
||||
$sql_extra = "";
|
||||
$sql_table = sprintf("`item` INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ",
|
||||
dbesc(protect_sprintf($search)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval(local_user()));
|
||||
|
||||
} else {
|
||||
if (get_config('system','use_fulltext_engine'))
|
||||
$sql_extra = sprintf(" AND MATCH (`item`.`body`, `item`.`title`) AGAINST ('%s' in boolean mode) ", dbesc(protect_sprintf($search)));
|
||||
else
|
||||
$sql_extra = sprintf(" AND `item`.`body` REGEXP '%s' ", dbesc(protect_sprintf(preg_quote($search))));
|
||||
}
|
||||
|
||||
}
|
||||
if(strlen($file)) {
|
||||
$sql_extra .= file_tag_file_query('item',unxmlify($file));
|
||||
}
|
||||
|
||||
if($conv) {
|
||||
$myurl = System::baseUrl() . '/profile/'. $a->user['nickname'];
|
||||
$myurl = substr($myurl,strpos($myurl,'://')+3);
|
||||
$myurl = str_replace('www.','',$myurl);
|
||||
$diasp_url = str_replace('/profile/','/u/',$myurl);
|
||||
|
||||
$sql_extra .= sprintf(" AND `item`.`parent` IN (SELECT distinct(`parent`) from item where `author-link` IN ('https://%s', 'http://%s') OR `mention`)",
|
||||
dbesc(protect_sprintf($myurl)),
|
||||
dbesc(protect_sprintf($myurl))
|
||||
);
|
||||
}
|
||||
|
||||
$pager_sql = sprintf(" LIMIT %d, %d ",intval($a->pager['start']), intval($a->pager['itemspage']));
|
||||
|
||||
|
||||
if($nouveau) {
|
||||
// "New Item View" - show all items unthreaded in reverse created date order
|
||||
|
||||
$items = q("SELECT `item`.*, `item`.`id` AS `item_id`,
|
||||
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, `contact`.`writable`,
|
||||
`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
|
||||
`contact`.`id` AS `cid`
|
||||
FROM $sql_table INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
|
||||
WHERE `item`.`uid` = %d AND `item`.`visible` = 1
|
||||
AND `item`.`deleted` = 0 and `item`.`moderated` = 0
|
||||
$simple_update
|
||||
AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
|
||||
$sql_extra $sql_nets
|
||||
ORDER BY `item`.`id` DESC $pager_sql ",
|
||||
intval($_SESSION['uid'])
|
||||
);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
// Normal conversation view
|
||||
|
||||
|
||||
if($order === 'post')
|
||||
$ordering = "`created`";
|
||||
else
|
||||
$ordering = "`commented`";
|
||||
|
||||
$start = dba_timer();
|
||||
|
||||
$r = q("SELECT `item`.`id` AS `item_id`, `contact`.`uid` AS `contact_uid`
|
||||
FROM $sql_table INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
|
||||
WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0
|
||||
AND `item`.`moderated` = 0 AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
|
||||
AND `item`.`parent` = `item`.`id`
|
||||
$sql_extra3 $sql_extra $sql_nets
|
||||
ORDER BY `item`.$ordering DESC $pager_sql ",
|
||||
intval(local_user())
|
||||
);
|
||||
|
||||
$first = dba_timer();
|
||||
|
||||
|
||||
// Then fetch all the children of the parents that are on this page
|
||||
|
||||
$parents_arr = array();
|
||||
$parents_str = '';
|
||||
|
||||
if (dbm::is_result($r)) {
|
||||
foreach($r as $rr)
|
||||
if(! in_array($rr['item_id'],$parents_arr))
|
||||
$parents_arr[] = $rr['item_id'];
|
||||
$parents_str = implode(', ', $parents_arr);
|
||||
|
||||
$items = q("SELECT `item`.*, `item`.`id` AS `item_id`,
|
||||
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`alias`, `contact`.`rel`, `contact`.`writable`,
|
||||
`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
|
||||
`contact`.`id` AS `cid`
|
||||
FROM $sql_table INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
|
||||
WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0
|
||||
AND `item`.`moderated` = 0
|
||||
AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
|
||||
AND `item`.`parent` IN ( %s )
|
||||
$sql_extra ",
|
||||
intval(local_user()),
|
||||
dbesc($parents_str)
|
||||
);
|
||||
|
||||
$second = dba_timer();
|
||||
|
||||
$items = conv_sort($items,$ordering);
|
||||
|
||||
} else {
|
||||
$items = array();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logger('parent dba_timer: ' . sprintf('%01.4f',$first - $start));
|
||||
logger('child dba_timer: ' . sprintf('%01.4f',$second - $first));
|
||||
|
||||
// Set this so that the conversation function can find out contact info for our wall-wall items
|
||||
$a->page_contact = $a->contact;
|
||||
|
||||
$mode = (($nouveau) ? 'network-new' : 'network');
|
||||
|
||||
$o = render_content($a,$items,$mode,false);
|
||||
|
||||
|
||||
header('Content-type: application/json');
|
||||
echo json_encode($o);
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function render_content(App $a, $items, $mode, $update, $preview = false) {
|
||||
|
||||
require_once('include/bbcode.php');
|
||||
require_once('mod/proxy.php');
|
||||
|
||||
$ssl_state = ((local_user()) ? true : false);
|
||||
|
||||
$profile_owner = 0;
|
||||
$page_writeable = false;
|
||||
|
||||
$previewing = (($preview) ? ' preview ' : '');
|
||||
|
||||
$edited = false;
|
||||
if (strcmp($item['created'], $item['edited'])<>0) {
|
||||
$edited = array(
|
||||
'label' => t('This entry was edited'),
|
||||
'date' => datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r'),
|
||||
'relative' => relative_date($item['edited'])
|
||||
);
|
||||
}
|
||||
|
||||
if($mode === 'network') {
|
||||
$profile_owner = local_user();
|
||||
$page_writeable = true;
|
||||
}
|
||||
|
||||
if($mode === 'profile') {
|
||||
$profile_owner = $a->profile['profile_uid'];
|
||||
$page_writeable = can_write_wall($a,$profile_owner);
|
||||
}
|
||||
|
||||
if($mode === 'notes') {
|
||||
$profile_owner = local_user();
|
||||
$page_writeable = true;
|
||||
}
|
||||
|
||||
if($mode === 'display') {
|
||||
$profile_owner = $a->profile['uid'];
|
||||
$page_writeable = can_write_wall($a,$profile_owner);
|
||||
}
|
||||
|
||||
if($mode === 'community') {
|
||||
$profile_owner = 0;
|
||||
$page_writeable = false;
|
||||
}
|
||||
|
||||
if($update)
|
||||
$return_url = $_SESSION['return_url'];
|
||||
else
|
||||
$return_url = $_SESSION['return_url'] = $a->query_string;
|
||||
|
||||
$cb = array('items' => $items, 'mode' => $mode, 'update' => $update, 'preview' => $preview);
|
||||
call_hooks('conversation_start',$cb);
|
||||
|
||||
$items = $cb['items'];
|
||||
|
||||
$cmnt_tpl = get_markup_template('comment_item.tpl');
|
||||
$tpl = 'wall_item.tpl';
|
||||
$wallwall = 'wallwall_item.tpl';
|
||||
$hide_comments_tpl = get_markup_template('hide_comments.tpl');
|
||||
|
||||
$conv_responses = array(
|
||||
'like' => array('title' => t('Likes','title')), 'dislike' => array('title' => t('Dislikes','title')),
|
||||
'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title'))
|
||||
);
|
||||
|
||||
|
||||
// array with html for each thread (parent+comments)
|
||||
$threads = array();
|
||||
$threadsid = -1;
|
||||
|
||||
if($items && count($items)) {
|
||||
|
||||
if($mode === 'network-new' || $mode === 'search' || $mode === 'community') {
|
||||
|
||||
// "New Item View" on network page or search page results
|
||||
// - just loop through the items and format them minimally for display
|
||||
|
||||
//$tpl = get_markup_template('search_item.tpl');
|
||||
$tpl = 'search_item.tpl';
|
||||
|
||||
foreach($items as $item) {
|
||||
$threadsid++;
|
||||
|
||||
$comment = '';
|
||||
$owner_url = '';
|
||||
$owner_photo = '';
|
||||
$owner_name = '';
|
||||
$sparkle = '';
|
||||
|
||||
if($mode === 'search' || $mode === 'community') {
|
||||
if(((activity_match($item['verb'],ACTIVITY_LIKE))
|
||||
|| (activity_match($item['verb'],ACTIVITY_DISLIKE))
|
||||
|| activity_match($item['verb'],ACTIVITY_ATTEND)
|
||||
|| activity_match($item['verb'],ACTIVITY_ATTENDNO)
|
||||
|| activity_match($item['verb'],ACTIVITY_ATTENDMAYBE))
|
||||
&& ($item['id'] != $item['parent']))
|
||||
continue;
|
||||
$nickname = $item['nickname'];
|
||||
}
|
||||
else
|
||||
$nickname = $a->user['nickname'];
|
||||
|
||||
// prevent private email from leaking.
|
||||
if($item['network'] === NETWORK_MAIL && local_user() != $item['uid'])
|
||||
continue;
|
||||
|
||||
$profile_name = ((strlen($item['author-name'])) ? $item['author-name'] : $item['name']);
|
||||
if($item['author-link'] && (! $item['author-name']))
|
||||
$profile_name = $item['author-link'];
|
||||
|
||||
|
||||
|
||||
$sp = false;
|
||||
$profile_link = best_link_url($item,$sp);
|
||||
if($profile_link === 'mailbox')
|
||||
$profile_link = '';
|
||||
if($sp)
|
||||
$sparkle = ' sparkle';
|
||||
else
|
||||
$profile_link = zrl($profile_link);
|
||||
|
||||
// Don't rely on the author-avatar. It is better to use the data from the contact table
|
||||
$author_contact = get_contact_details_by_url($item['author-link'], $profile_owner);
|
||||
if ($author_contact["thumb"])
|
||||
$profile_avatar = $author_contact["thumb"];
|
||||
else
|
||||
$profile_avatar = $item['author-avatar'];
|
||||
|
||||
$locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => '');
|
||||
call_hooks('render_location',$locate);
|
||||
|
||||
$location = ((strlen($locate['html'])) ? $locate['html'] : render_location_dummy($locate));
|
||||
|
||||
localize_item($item);
|
||||
if($mode === 'network-new')
|
||||
$dropping = true;
|
||||
else
|
||||
$dropping = false;
|
||||
|
||||
|
||||
$drop = array(
|
||||
'dropping' => $dropping,
|
||||
'select' => t('Select'),
|
||||
'delete' => t('Delete'),
|
||||
);
|
||||
|
||||
$star = false;
|
||||
$isstarred = "unstarred";
|
||||
|
||||
$lock = false;
|
||||
$likebuttons = false;
|
||||
$shareable = false;
|
||||
|
||||
$body = prepare_body($item,true);
|
||||
|
||||
if($a->theme['template_engine'] === 'internal') {
|
||||
$name_e = template_escape($profile_name);
|
||||
$title_e = template_escape($item['title']);
|
||||
$body_e = template_escape($body);
|
||||
$text_e = strip_tags(template_escape($body));
|
||||
$location_e = template_escape($location);
|
||||
$owner_name_e = template_escape($owner_name);
|
||||
}
|
||||
else {
|
||||
$name_e = $profile_name;
|
||||
$title_e = $item['title'];
|
||||
$body_e = $body;
|
||||
$text_e = strip_tags($body);
|
||||
$location_e = $location;
|
||||
$owner_name_e = $owner_name;
|
||||
}
|
||||
|
||||
//$tmp_item = replace_macros($tpl,array(
|
||||
$tmp_item = array(
|
||||
'template' => $tpl,
|
||||
'id' => (($preview) ? 'P0' : $item['item_id']),
|
||||
'linktitle' => sprintf( t('View %s\'s profile @ %s'), $profile_name, ((strlen($item['author-link'])) ? $item['author-link'] : $item['url'])),
|
||||
'profile_url' => $profile_link,
|
||||
'item_photo_menu' => item_photo_menu($item),
|
||||
'name' => $name_e,
|
||||
'sparkle' => $sparkle,
|
||||
'lock' => $lock,
|
||||
'thumb' => proxy_url($profile_avatar, false, PROXY_SIZE_THUMB),
|
||||
'title' => $title_e,
|
||||
'body' => $body_e,
|
||||
'text' => $text_e,
|
||||
'ago' => (($item['app']) ? sprintf( t('%s from %s'),relative_date($item['created']),$item['app']) : relative_date($item['created'])),
|
||||
'location' => $location_e,
|
||||
'indent' => '',
|
||||
'owner_name' => $owner_name_e,
|
||||
'owner_url' => $owner_url,
|
||||
'owner_photo' => proxy_url($owner_photo, false, PROXY_SIZE_THUMB),
|
||||
'plink' => get_plink($item),
|
||||
'edpost' => false,
|
||||
'isstarred' => $isstarred,
|
||||
'star' => $star,
|
||||
'drop' => $drop,
|
||||
'vote' => $likebuttons,
|
||||
'like' => '',
|
||||
'dislike' => '',
|
||||
'comment' => '',
|
||||
//'conv' => (($preview) ? '' : array('href'=> System::baseUrl($ssl_state) . '/display/' . $nickname . '/' . $item['id'], 'title'=> t('View in context'))),
|
||||
'conv' => (($preview) ? '' : array('href'=> System::baseUrl($ssl_state).'/display/'.$item['guid'], 'title'=> t('View in context'))),
|
||||
'previewing' => $previewing,
|
||||
'wait' => t('Please wait'),
|
||||
);
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
call_hooks('display_item', $arr);
|
||||
|
||||
$threads[$threadsid]['id'] = $item['item_id'];
|
||||
$threads[$threadsid]['items'] = array($arr['output']);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal View
|
||||
|
||||
|
||||
// Figure out how many comments each parent has
|
||||
// (Comments all have gravity of 6)
|
||||
// Store the result in the $comments array
|
||||
|
||||
$comments = array();
|
||||
foreach($items as $item) {
|
||||
if((intval($item['gravity']) == 6) && ($item['id'] != $item['parent'])) {
|
||||
if(! x($comments,$item['parent']))
|
||||
$comments[$item['parent']] = 1;
|
||||
else
|
||||
$comments[$item['parent']] += 1;
|
||||
} elseif(! x($comments,$item['parent']))
|
||||
$comments[$item['parent']] = 0; // avoid notices later on
|
||||
}
|
||||
|
||||
// map all the like/dislike/attendance activities for each parent item
|
||||
// Store these in the $alike and $dlike arrays
|
||||
|
||||
foreach($items as $item) {
|
||||
builtin_activity_puller($item, $conv_responses);
|
||||
}
|
||||
|
||||
$comments_collapsed = false;
|
||||
$comments_seen = 0;
|
||||
$comment_lastcollapsed = false;
|
||||
$comment_firstcollapsed = false;
|
||||
$blowhard = 0;
|
||||
$blowhard_count = 0;
|
||||
|
||||
|
||||
foreach($items as $item) {
|
||||
|
||||
$comment = '';
|
||||
$template = $tpl;
|
||||
$commentww = '';
|
||||
$sparkle = '';
|
||||
$owner_url = $owner_photo = $owner_name = '';
|
||||
|
||||
// We've already parsed out like/dislike for special treatment. We can ignore them now
|
||||
|
||||
if(((activity_match($item['verb'],ACTIVITY_LIKE))
|
||||
|| (activity_match($item['verb'],ACTIVITY_DISLIKE)
|
||||
|| activity_match($item['verb'],ACTIVITY_ATTEND)
|
||||
|| activity_match($item['verb'],ACTIVITY_ATTENDNO)
|
||||
|| activity_match($item['verb'],ACTIVITY_ATTENDMAYBE)))
|
||||
&& ($item['id'] != $item['parent']))
|
||||
continue;
|
||||
|
||||
$toplevelpost = (($item['id'] == $item['parent']) ? true : false);
|
||||
|
||||
|
||||
// Take care of author collapsing and comment collapsing
|
||||
// (author collapsing is currently disabled)
|
||||
// If a single author has more than 3 consecutive top-level posts, squash the remaining ones.
|
||||
// If there are more than two comments, squash all but the last 2.
|
||||
|
||||
if($toplevelpost) {
|
||||
|
||||
$item_writeable = (($item['writable'] || $item['self']) ? true : false);
|
||||
|
||||
$comments_seen = 0;
|
||||
$comments_collapsed = false;
|
||||
$comment_lastcollapsed = false;
|
||||
$comment_firstcollapsed = false;
|
||||
|
||||
$threadsid++;
|
||||
$threads[$threadsid]['id'] = $item['item_id'];
|
||||
$threads[$threadsid]['private'] = $item['private'];
|
||||
$threads[$threadsid]['items'] = array();
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
// prevent private email reply to public conversation from leaking.
|
||||
if($item['network'] === NETWORK_MAIL && local_user() != $item['uid'])
|
||||
continue;
|
||||
|
||||
$comments_seen ++;
|
||||
$comment_lastcollapsed = false;
|
||||
$comment_firstcollapsed = false;
|
||||
}
|
||||
|
||||
$override_comment_box = ((($page_writeable) && ($item_writeable)) ? true : false);
|
||||
$show_comment_box = ((($page_writeable) && ($item_writeable) && ($comments_seen == $comments[$item['parent']])) ? true : false);
|
||||
|
||||
|
||||
if(($comments[$item['parent']] > 2) && ($comments_seen <= ($comments[$item['parent']] - 2)) && ($item['gravity'] == 6)) {
|
||||
|
||||
if (!$comments_collapsed){
|
||||
$threads[$threadsid]['num_comments'] = sprintf( tt('%d comment','%d comments',$comments[$item['parent']]),$comments[$item['parent']] );
|
||||
$threads[$threadsid]['hidden_comments_num'] = $comments[$item['parent']];
|
||||
$threads[$threadsid]['hidden_comments_text'] = tt('comment', 'comments', $comments[$item['parent']]);
|
||||
$threads[$threadsid]['hide_text'] = t('show more');
|
||||
$comments_collapsed = true;
|
||||
$comment_firstcollapsed = true;
|
||||
}
|
||||
}
|
||||
if(($comments[$item['parent']] > 2) && ($comments_seen == ($comments[$item['parent']] - 1))) {
|
||||
|
||||
$comment_lastcollapsed = true;
|
||||
}
|
||||
|
||||
$redirect_url = 'redir/' . $item['cid'] ;
|
||||
|
||||
$lock = ((($item['private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|
||||
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
|
||||
? t('Private Message')
|
||||
: false);
|
||||
|
||||
|
||||
// Top-level wall post not written by the wall owner (wall-to-wall)
|
||||
// First figure out who owns it.
|
||||
|
||||
$osparkle = '';
|
||||
|
||||
if(($toplevelpost) && (! $item['self']) && ($mode !== 'profile')) {
|
||||
|
||||
if($item['wall']) {
|
||||
|
||||
// On the network page, I am the owner. On the display page it will be the profile owner.
|
||||
// This will have been stored in $a->page_contact by our calling page.
|
||||
// Put this person as the wall owner of the wall-to-wall notice.
|
||||
|
||||
$owner_url = zrl($a->page_contact['url']);
|
||||
$owner_photo = $a->page_contact['thumb'];
|
||||
$owner_name = $a->page_contact['name'];
|
||||
$template = $wallwall;
|
||||
$commentww = 'ww';
|
||||
}
|
||||
|
||||
if((! $item['wall']) && $item['owner-link']) {
|
||||
|
||||
$owner_linkmatch = (($item['owner-link']) && link_compare($item['owner-link'],$item['author-link']));
|
||||
$alias_linkmatch = (($item['alias']) && link_compare($item['alias'],$item['author-link']));
|
||||
$owner_namematch = (($item['owner-name']) && $item['owner-name'] == $item['author-name']);
|
||||
if((! $owner_linkmatch) && (! $alias_linkmatch) && (! $owner_namematch)) {
|
||||
|
||||
// The author url doesn't match the owner (typically the contact)
|
||||
// and also doesn't match the contact alias.
|
||||
// The name match is a hack to catch several weird cases where URLs are
|
||||
// all over the park. It can be tricked, but this prevents you from
|
||||
// seeing "Bob Smith to Bob Smith via Wall-to-wall" and you know darn
|
||||
// well that it's the same Bob Smith.
|
||||
|
||||
// But it could be somebody else with the same name. It just isn't highly likely.
|
||||
|
||||
|
||||
$owner_url = $item['owner-link'];
|
||||
$owner_photo = $item['owner-avatar'];
|
||||
$owner_name = $item['owner-name'];
|
||||
$template = $wallwall;
|
||||
$commentww = 'ww';
|
||||
// If it is our contact, use a friendly redirect link
|
||||
if((link_compare($item['owner-link'],$item['url']))
|
||||
&& ($item['network'] === NETWORK_DFRN)) {
|
||||
$owner_url = $redirect_url;
|
||||
$osparkle = ' sparkle';
|
||||
}
|
||||
else
|
||||
$owner_url = zrl($owner_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$likebuttons = '';
|
||||
$shareable = ((($profile_owner == local_user()) && ($item['private'] != 1)) ? true : false);
|
||||
|
||||
if($page_writeable) {
|
||||
/* if($toplevelpost) { */
|
||||
$likebuttons = array(
|
||||
'like' => array( t("I like this \x28toggle\x29"), t("like")),
|
||||
'dislike' => array( t("I don't like this \x28toggle\x29"), t("dislike")),
|
||||
);
|
||||
if ($shareable) $likebuttons['share'] = array( t('Share this'), t('share'));
|
||||
/* } */
|
||||
|
||||
$qc = $qcomment = null;
|
||||
|
||||
if(in_array('qcomment',$a->plugins)) {
|
||||
$qc = ((local_user()) ? get_pconfig(local_user(),'qcomment','words') : null);
|
||||
$qcomment = (($qc) ? explode("\n",$qc) : null);
|
||||
}
|
||||
|
||||
if(($show_comment_box) || (($show_comment_box == false) && ($override_comment_box == false) && ($item['last-child']))) {
|
||||
$comment = replace_macros($cmnt_tpl,array(
|
||||
'$return_path' => '',
|
||||
'$jsreload' => (($mode === 'display') ? $_SESSION['return_url'] : ''),
|
||||
'$type' => (($mode === 'profile') ? 'wall-comment' : 'net-comment'),
|
||||
'$id' => $item['item_id'],
|
||||
'$parent' => $item['parent'],
|
||||
'$qcomment' => $qcomment,
|
||||
'$profile_uid' => $profile_owner,
|
||||
'$mylink' => $a->contact['url'],
|
||||
'$mytitle' => t('This is you'),
|
||||
'$myphoto' => $a->contact['thumb'],
|
||||
'$comment' => t('Comment'),
|
||||
'$submit' => t('Submit'),
|
||||
'$edbold' => t('Bold'),
|
||||
'$editalic' => t('Italic'),
|
||||
'$eduline' => t('Underline'),
|
||||
'$edquote' => t('Quote'),
|
||||
'$edcode' => t('Code'),
|
||||
'$edimg' => t('Image'),
|
||||
'$edurl' => t('Link'),
|
||||
'$edvideo' => t('Video'),
|
||||
'$preview' => t('Preview'),
|
||||
'$sourceapp' => t($a->sourcename),
|
||||
'$ww' => (($mode === 'network') ? $commentww : ''),
|
||||
'$rand_num' => random_digits(12)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (local_user() && link_compare($a->contact['url'],$item['author-link'])) {
|
||||
$edpost = array(System::baseUrl($ssl_state)."/editpost/".$item['id'], t("Edit"));
|
||||
} else {
|
||||
$edpost = false;
|
||||
}
|
||||
|
||||
$drop = '';
|
||||
$dropping = false;
|
||||
|
||||
if((intval($item['contact-id']) && $item['contact-id'] == remote_user()) || ($item['uid'] == local_user()))
|
||||
$dropping = true;
|
||||
|
||||
$drop = array(
|
||||
'dropping' => $dropping,
|
||||
'select' => t('Select'),
|
||||
'delete' => t('Delete'),
|
||||
);
|
||||
|
||||
$star = false;
|
||||
$filer = false;
|
||||
|
||||
$isstarred = "unstarred";
|
||||
if ($profile_owner == local_user()) {
|
||||
if ($toplevelpost) {
|
||||
$isstarred = (($item['starred']) ? "starred" : "unstarred");
|
||||
|
||||
$star = array(
|
||||
'do' => t("add star"),
|
||||
'undo' => t("remove star"),
|
||||
'toggle' => t("toggle star status"),
|
||||
'classdo' => (($item['starred']) ? "hidden" : ""),
|
||||
'classundo' => (($item['starred']) ? "" : "hidden"),
|
||||
'starred' => t('starred'),
|
||||
'tagger' => t("add tag"),
|
||||
'classtagger' => "",
|
||||
);
|
||||
|
||||
$r = q("SELECT `ignored` FROM `thread` WHERE `uid` = %d AND `iid` = %d LIMIT 1",
|
||||
intval($item['uid']),
|
||||
intval($item['id'])
|
||||
);
|
||||
|
||||
if (dbm::is_result($r)) {
|
||||
$ignore = array(
|
||||
'do' => t("ignore thread"),
|
||||
'undo' => t("unignore thread"),
|
||||
'toggle' => t("toggle ignore status"),
|
||||
'classdo' => (($r[0]['ignored']) ? "hidden" : ""),
|
||||
'classundo' => (($r[0]['ignored']) ? "" : "hidden"),
|
||||
'ignored' => t('ignored'),
|
||||
);
|
||||
}
|
||||
$tagger = '';
|
||||
if (feature_enabled($profile_owner,'commtag')) {
|
||||
$tagger = array(
|
||||
'add' => t("add tag"),
|
||||
'class' => "",
|
||||
);
|
||||
}
|
||||
}
|
||||
$filer = t("save to folder");
|
||||
}
|
||||
|
||||
|
||||
$photo = $item['photo'];
|
||||
$thumb = $item['thumb'];
|
||||
|
||||
// Post was remotely authored.
|
||||
|
||||
$diff_author = ((link_compare($item['url'],$item['author-link'])) ? false : true);
|
||||
|
||||
$profile_name = (((strlen($item['author-name'])) && $diff_author) ? $item['author-name'] : $item['name']);
|
||||
|
||||
if($item['author-link'] && (! $item['author-name']))
|
||||
$profile_name = $item['author-link'];
|
||||
|
||||
$sp = false;
|
||||
$profile_link = best_link_url($item,$sp);
|
||||
if ($profile_link === 'mailbox') {
|
||||
$profile_link = '';
|
||||
}
|
||||
if ($sp) {
|
||||
$sparkle = ' sparkle';
|
||||
} else {
|
||||
$profile_link = zrl($profile_link);
|
||||
}
|
||||
|
||||
// Don't rely on the author-avatar. It is better to use the data from the contact table
|
||||
$author_contact = get_contact_details_by_url($item['author-link'], $profile_owner);
|
||||
if ($author_contact["thumb"]) {
|
||||
$profile_avatar = $author_contact["thumb"];
|
||||
} else {
|
||||
$profile_avatar = $item['author-avatar'];
|
||||
}
|
||||
|
||||
$like = ((x($conv_responses['like'],$item['uri'])) ? format_like($conv_responses['like'][$item['uri']],$conv_responses['like'][$item['uri'] . '-l'],'like',$item['uri']) : '');
|
||||
$dislike = ((x($conv_responses['dislike'],$item['uri'])) ? format_like($conv_responses['dislike'][$item['uri']],$conv_responses['dislike'][$item['uri'] . '-l'],'dislike',$item['uri']) : '');
|
||||
|
||||
// process action responses - e.g. like/dislike/attend/agree/whatever
|
||||
$response_verbs = array('like');
|
||||
if(feature_enabled($profile_owner,'dislike'))
|
||||
$response_verbs[] = 'dislike';
|
||||
if($item['object-type'] === ACTIVITY_OBJ_EVENT) {
|
||||
$response_verbs[] = 'attendyes';
|
||||
$response_verbs[] = 'attendno';
|
||||
$response_verbs[] = 'attendmaybe';
|
||||
if($page_writeable) {
|
||||
$isevent = true;
|
||||
$attend = array( t('I will attend'), t('I will not attend'), t('I might attend'));
|
||||
}
|
||||
}
|
||||
$responses = get_responses($conv_responses,$response_verbs,'',$item);
|
||||
|
||||
$locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => '');
|
||||
call_hooks('render_location',$locate);
|
||||
|
||||
$location = ((strlen($locate['html'])) ? $locate['html'] : render_location_dummy($locate));
|
||||
|
||||
$indent = (($toplevelpost) ? '' : ' comment');
|
||||
|
||||
$shiny = "";
|
||||
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
|
||||
$shiny = 'shiny';
|
||||
|
||||
//
|
||||
localize_item($item);
|
||||
|
||||
|
||||
$tags=array();
|
||||
foreach(explode(',',$item['tag']) as $tag){
|
||||
$tag = trim($tag);
|
||||
if ($tag!="") $tags[] = bbcode($tag);
|
||||
}
|
||||
|
||||
// Build the HTML
|
||||
|
||||
$body = prepare_body($item,true);
|
||||
//$tmp_item = replace_macros($template,
|
||||
|
||||
if($a->theme['template_engine'] === 'internal') {
|
||||
$body_e = template_escape($body);
|
||||
$text_e = strip_tags(template_escape($body));
|
||||
$name_e = template_escape($profile_name);
|
||||
$title_e = template_escape($item['title']);
|
||||
$location_e = template_escape($location);
|
||||
$owner_name_e = template_escape($owner_name);
|
||||
}
|
||||
else {
|
||||
$body_e = $body;
|
||||
$text_e = strip_tags($body);
|
||||
$name_e = $profile_name;
|
||||
$title_e = $item['title'];
|
||||
$location_e = $location;
|
||||
$owner_name_e = $owner_name;
|
||||
}
|
||||
|
||||
$tmp_item = array(
|
||||
// collapse comments in template. I don't like this much...
|
||||
'comment_firstcollapsed' => $comment_firstcollapsed,
|
||||
'comment_lastcollapsed' => $comment_lastcollapsed,
|
||||
// template to use to render item (wall, walltowall, search)
|
||||
'template' => $template,
|
||||
|
||||
'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
|
||||
'tags' => $tags,
|
||||
'body' => $body_e,
|
||||
'text' => $text_e,
|
||||
'id' => $item['item_id'],
|
||||
'isevent' => $isevent,
|
||||
'attend' => $attend,
|
||||
'linktitle' => sprintf( t('View %s\'s profile @ %s'), $profile_name, ((strlen($item['author-link'])) ? $item['author-link'] : $item['url'])),
|
||||
'olinktitle' => sprintf( t('View %s\'s profile @ %s'), $profile_name, ((strlen($item['owner-link'])) ? $item['owner-link'] : $item['url'])),
|
||||
'to' => t('to'),
|
||||
'wall' => t('Wall-to-Wall'),
|
||||
'vwall' => t('via Wall-To-Wall:'),
|
||||
'profile_url' => $profile_link,
|
||||
'item_photo_menu' => item_photo_menu($item),
|
||||
'name' => $name_e,
|
||||
'thumb' => proxy_url($profile_avatar, false, PROXY_SIZE_THUMB),
|
||||
'osparkle' => $osparkle,
|
||||
'sparkle' => $sparkle,
|
||||
'title' => $title_e,
|
||||
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
|
||||
'ago' => (($item['app']) ? sprintf( t('%s from %s'),relative_date($item['created']),$item['app']) : relative_date($item['created'])),
|
||||
'app' => $item['app'],
|
||||
'created' => relative_date($item['created']),
|
||||
'lock' => $lock,
|
||||
'location' => $location_e,
|
||||
'indent' => $indent,
|
||||
'shiny' => $shiny,
|
||||
'owner_url' => $owner_url,
|
||||
'owner_photo' => proxy_url($owner_photo, false, PROXY_SIZE_THUMB),
|
||||
'owner_name' => $owner_name_e,
|
||||
'plink' => get_plink($item),
|
||||
'edpost' => $edpost,
|
||||
'isstarred' => $isstarred,
|
||||
'star' => $star,
|
||||
'ignore' => ((feature_enabled($profile_owner,'ignore_posts')) ? $ignore : ''),
|
||||
'tagger' => $tagger,
|
||||
'filer' => ((feature_enabled($profile_owner,'filing')) ? $filer : ''),
|
||||
'drop' => $drop,
|
||||
'vote' => $likebuttons,
|
||||
'responses' => $responses,
|
||||
'like' => $like,
|
||||
'dislike' => $dislike,
|
||||
'switchcomment' => t('Comment'),
|
||||
'comment' => $comment,
|
||||
'previewing' => $previewing,
|
||||
'wait' => t('Please wait'),
|
||||
'edited' => $edited,
|
||||
'network' => $item["item_network"],
|
||||
'network_name' => network_to_name($item['network'], $profile_link),
|
||||
|
||||
);
|
||||
|
||||
|
||||
$arr = array('item' => $item, 'output' => $tmp_item);
|
||||
call_hooks('display_item', $arr);
|
||||
|
||||
$threads[$threadsid]['items'][] = $arr['output'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $threads;
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user