kopia lustrzana https://github.com/friendica/friendica
Removed stuff that was never used or isn't used anymore
rodzic
1b53b8cae9
commit
69afe50345
|
@ -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();
|
||||
}
|
||||
}
|
Plik diff jest za duży
Load Diff
Plik diff jest za duży
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;
|
||||
|
||||
}
|
Ładowanie…
Reference in New Issue